Назначение struct, typedef struct, в С++

В С++ можно создать структуру:

struct MyStruct
{
    ...
}

А также можно сделать следующее:

typedef struct
{
    ...
} MyStruct;

И все же, насколько я могу судить, никакой заметной разницы между ними. Что предпочтительнее? Почему оба пути существуют, если нет разницы? Является ли лучше, чем другой по стилю или читабельности?

Ответы

Ответ 1

Версия typedef является частным случаем

typedef foo bar;

который определяет новый "тип" в качестве псевдонима для foo. В вашем случае foo оказывается структурой. В C это был единственный способ ввести новые "типы" (в кавычках, потому что они на самом деле не эквивалентны int, float и co). В С++ это не так полезно, потому что С++ был разработан, чтобы сделать определение новых типов более легким и более полным, чем C (по крайней мере, в начале С++), и typedef даже не нужно ссылаться на ранее объявленную структуру ( или класс).

Ответ 2

Вот различия между двумя объявлениями/определениями:


1) Вы не можете использовать имя typedef для идентификации конструктора или деструктора

struct MyStruct { MyStruct(); ~MyStruct(); }; // ok

typedef struct { MyStructTD(); ~MyStructTD(); } MyStructTD; // not ok

// now consider 
typedef struct MyStruct2 { MyStruct2(); } MyStructTD2; // ok

MyStructTD2::MyStruct2() { } // ok
MyStructTD2::MyStructTD2() { } // not ok

2) Вы не можете скрыть имя typedef, например, имя, введенное через class-head, или, наоборот, если у вас уже есть функция или объект с определенным именем, вы все равно можете объявить класс с этим именем, используя class-head, но не с помощью метода typedef.

struct MyStruct { }; // ok

typedef struct { } MyStructTD; // ok

void MyStruct() { }  // (1) - ok Hides struct MyStruct
void MyStructTD() { }  // (2) - not-ok - ill-formed

//> Or if you flip it around, consider in a new translation unit:

void MyStruct() { }   // ok
void MyStructTD() { }   // ok

struct MyStruct { }; // ok
typedef struct { } MyStructTD; // Not ok

3) Вы не можете использовать имя typedef в специфицированном спецификаторе типа

struct MyStruct {  }; // ok

typedef struct { } MyStructTD; // ok

int main()
{
  void MyStruct(); 
  void MyStructTD(); // ok - new declarative region

  struct MyStruct ms; // ok - names the type
  struct MyStructTD ms2; // not ok - cannot use typedef-name here

}

struct AnotherStruct 
{ 
    friend struct MyStruct;  // ok
    friend struct MyStructTD; // not ok
};

4) Вы не можете использовать его для определения вложенных структур

struct S { struct M; };

typedef struct { } S::M;  // not ok

struct S::M { }; // ok

Как вы можете видеть, между ними существует заметная разница. Некоторые из причуд typedefs являются результатом совместимости C (что в основном связано с тем, что оба пути существуют, я считаю) - и в большинстве случаев объявление названия в классе-голове более естественное С++ - оно имеет свои преимущества (особенно когда вы необходимо определить конструкторы и деструкторы), и поэтому предпочтительнее. Если вы пишете код, который должен быть совместимым с C и С++, тогда есть преимущество в использовании обоих подходов. Но если вы пишете чистый С++, я считаю, что определение имени класса в классе-голове должно быть более читаемым.

Ответ 3

Последний существует для совместимости с C - используйте первый в новом коде С++.

Ответ 4

Вы должны использовать typedef, поэтому вам не нужно указывать ключевое слово struct при объявлении переменных этой структуры.

Без typedef:

struct MyStruct foo;

С typedef:

MyStruct foo;

В основном вы создаете MyStruct как новый тип, поэтому он также реализует некоторый уровень абстракции типа, поскольку программистам не нужно явно знать, какой тип он есть. Вы можете передать MyStruct в функцию, манипулировать данными в ней и вернуть ее, и программисту не нужно беспокоиться о том, что на самом деле происходит.

Значительная часть стандартной библиотеки C использует typedefs по этой причине.

Ответ 5

Есть много ответов, которые рассматривают оба подхода как эквивалентные, но они не являются.

Ключевое слово typedef используется для создания псевдонима типа, то есть оно предоставляет новый способ обращения к другому типу. Когда вы используете typedef struct {} XXX;, вы фактически создаете неназванный тип, а затем создаете псевдоним XXX для этого неназванного типа. С другой стороны, при вводе struct XXX {}.

Пожалуйста, прочитайте ответ Michael Burr здесь (это лучший ответ, чем тот, который был принят для этого вопроса.

Ответ 6

"Структура MyStruct {};" Конструкция неявно определяет эквивалентный typedef, поэтому обычно это будет предпочтительным современным использованием. Есть еще некоторые виды использования для typedef, в основном с типами указателей для структур. Например.

typedef struct MyStruct* MyStructPtr;