Pergunta

C ++, não existe qualquer diferença entre:

struct Foo { ... };

e

typedef struct { ... } Foo;
Foi útil?

Solução

Em C ++, há apenas uma diferença sutil. É um resquício de C, em que ele faz a diferença.

O padrão de linguagem C ( C89 §3.1.2.3 , C99 §6.2.3 , e namespaces C11 §6.2.3 ) mandatos separados para diferentes categorias de identificadores, incluindo < em> identificadores tag (para struct / union / enum) e identificadores comuns (para typedef e outros identificadores).

Se você acabou de dizer:

struct Foo { ... };
Foo x;

que se obtém um erro do compilador, porque Foo só é definida no namespace tag.

Você teria que declará-lo como:

struct Foo x;

Toda vez que você quer para se referir a um Foo, você sempre tem que chamá-lo um struct Foo. Isto torna-se rápido irritante, por isso você pode adicionar um typedef:

struct Foo { ... };
typedef struct Foo Foo;

Agora struct Foo (no namespace tag) e apenas Foo simples (no namespace identificador comum), ambos se referem à mesma coisa, e você pode declarar livremente objetos do tipo Foo sem a palavra-chave struct.


A construção:

typedef struct Foo { ... } Foo;

é apenas uma abreviação para a declaração e typedef.


Finalmente,

typedef struct { ... } Foo;

declara uma estrutura anônima e cria um typedef para ele. Assim, com esta construção, ele não tem um nome no namespace tag, apenas um nome no namespace typedef. Isso significa que ele também não pode ser voltada para o declarado. Se você quiser fazer uma declaração para a frente, você tem que dar-lhe um nome no namespace tag .


Em C ++, todos struct / union / enum / class declarações agir como estão typedef'ed implicitamente, desde que o nome não está oculta por outra declaração com o mesmo nome. Consulte Michael Burr resposta para os detalhes completos .

Outras dicas

Na este artigo DDJ , Dan Saks explica uma pequena área onde os erros podem rastejar através se você não typedef suas estruturas (e classes!):

Se você quiser, você pode imaginar que C ++ gera um typedef para cada tag nome, como

typedef class string string;

Infelizmente, isso não é inteiramente preciso. Eu gostaria que fosse assim tão simples, Mas isso não. C ++ não é possível gerar tais typedefs para estruturas, sindicatos, ou enums sem a introdução de incompatibilidades com C.

Por exemplo, suponha que um programa C declara tanto uma função e um struct estado chamado:

int status(); struct status;

Mais uma vez, isso pode ser má prática, mas é C. Neste programa, status (por si) refere-se à função; struct estatuto se refere ao tipo.

Se C ++ gerou automaticamente typedefs para tags, então quando você compilado este programa, tal como C ++, a compilador geraria:

typedef struct status status;

Infelizmente, este tipo nome seria entrar em conflito com o nome da função, e o programa não compilar. Isso é porque C ++ não pode simplesmente gerar um typedef para cada tag.

Em C ++, etiquetas de agir apenas como typedef nomes, exceto que uma lata programa declarar, uma função de objecto, ou enumerador com o mesmo nome ea mesmo alcance como uma etiqueta. Nesse caso, o objeto, função, ou o nome do entrevistador esconde o nome da marca. A lata programa referem-se ao nome da marca somente usando a palavra-chave class, struct, união, ou enum (como apropriado) em frente do nome da marca. Um nome de tipo constituído por uma dessas palavras-chave, seguido por um Tag é um especificador de tipo-elaborada. Por exemplo, o estado struct e enum mês são elaborados-type-especificadores.

Assim, um programa C que contém:

int status(); struct status;

se comporta da mesma quando compilado como C ++. O estado nome sozinho refere-se a função. O programa pode se referir ao digitar somente usando o elaborada de tipo-especificador struct status.

Assim como este permitem erros a rastejar em programas? Considere o programa em Listagem 1 . Isso define o programa A foo classe com um construtor padrão, e um operador de conversão que converte um objeto foo para const char *. A expressão

p = foo();

no principal deve construir um objeto foo e aplicar o operador de conversão. o declaração de saída posterior

cout << p << '\n';

deve exibir classe foo, mas não. Ele exibe função foo.

Este resultado surpreendente ocorre porque o programa inclui lib.h cabeçalho mostrado na Listagem 2 . este cabeçalho define uma função também chamado foo. o nome da função foo esconde o nome da classe foo, de modo que a referência a foo na página refere-se à função, não a classe. principal pode referir-se à classe apenas por utilizando um-tipo-especificador elaborado, conforme em

p = class foo();

A maneira de evitar tal confusão ao longo do programa é adicionar o seguinte typedef para o nome da classe foo:

typedef class foo foo;

imediatamente antes ou depois da aula definição. Isso faz com que um typedef conflito entre o foo nome do tipo e o nome da função foo (a partir da biblioteca) que irá acionar um em tempo de compilação erro.

Eu sei de ninguém que realmente escreve estes typedefs como uma questão de disciplina. Ela exige muita disciplina. Desde a a incidência de erros, como a um em Listagem 1 é provavelmente muito pequeno, você muitos nunca entrar em conflito com este problema. Mas se um erro em sua software pode causar lesões corporais, então você deve escrever os typedefs não importa como unlikely o erro.

Eu não posso imaginar por que alguém iria nunca quer esconder um nome de classe com um função ou nome de objecto na mesma âmbito da classe. As regras esconderijos na C foi um erro, e que deveriam Não foram estendidos para aulas de C ++. Na verdade, você pode corrigir o erro, mas requer adicional disciplina e esforço que a programação não deve ser necessário.

Uma diferença mais importante: typedefs pode não ser para a frente declarado. Assim, para a opção typedef você deve #include o arquivo que contém o typedef, ou seja, tudo o que #includes seu .h também inclui esse arquivo se ele precisa diretamente ou não, e assim por diante. Ele pode definitivamente afetar seus tempos de compilação em projetos maiores.

Sem o typedef, em alguns casos, você pode simplesmente adicionar uma declaração para a frente de struct Foo; na parte superior do seu arquivo .h, e só #include a definição struct em seu arquivo .cpp.

Não é a diferença, mas sutil. Olhe isto deste modo: struct Foo introduz um novo tipo. O segundo cria um alias chamado Foo (e não um novo tipo) para um tipo de struct sem nome.

7.1.3 O typedef especificador

1 [...]

Um nome declarado com o especificador typedef torna-se um nome de typedef. No âmbito da sua declaração, uma typedef nome é sintaticamente equivalente a uma palavra-chave e nomes o tipo associado com o identificador em o modo descrito na cláusula 8. Um typedef-nome é, assim, um sinónimo de outro tipo. Um typedef-name não introduzir um novo tipo a maneira como uma declaração de classe (9,1) ou declaração enum faz.

8 Se a declaração typedef define uma classe sem nome (ou enum), o primeiro typedef-nome declarado pela declaração ser a de que tipo de classe (ou tipo de enumeração) é utilizado para denotar o tipo de classe (ou tipo de enumeração) para ligao fins única (3,5). [Exemplo:

typedef struct { } *ps, S; // S is the class name for linkage purposes

Assim, um typedef sempre é usado como um espaço reservado / sinônimo de outro tipo.

Você não pode usar a declaração para a frente com o struct typedef.

A estrutura em si é um tipo anônimo, para que você não tem um nome real para declarar a frente.

typedef struct{
    int one;
    int two;
}myStruct;

A declaração para a frente como isso vai funcionar:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types

Struct é criar um tipo de dados. O typedef é definir um apelido para um tipo de dados.

Uma diferença importante entre um 'typedef struct' e uma 'estrutura' em C ++ é que membro inline inicialização em 'typedef struct' não vai funcionar.

// the 'x' in this struct will NOT be initialised to zero
typedef struct { int x = 0; } Foo;

// the 'x' in this struct WILL be initialised to zero
struct Foo { int x = 0; };

Não há nenhuma diferença em C ++, mas eu acredito em C que lhe permitiria declarar instâncias do struct Foo sem fazer explicitamente:

struct Foo bar;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top