Какова цель определения типов в C ++? - PullRequest
10 голосов
/ 05 июня 2009

Я часто видел код, подобный следующему, в некотором коде C ++, на который я смотрю:

typedef class SomeClass SomeClass;

Я озадачен тем, чего это на самом деле достигает. Кажется, это ничего не изменит. Что делают typedef как это? И если это что-то полезное, стоит ли дополнительных усилий?

Ответы [ 7 ]

20 голосов
/ 05 июня 2009

Это предотвращает компиляцию кода, подобного этому:

class SomeClass { ... };
int SomeClass;

Это совершенно законный C ++, хотя ужасен . Если вы сделаете это, то любые ссылки на голые SomeClass ссылаются на переменную. Чтобы обратиться к классу, вам нужно явно сказать class SomeClass при каждом использовании. Если вы создаете typedef:

class SomeClass { ... };
typedef class SomeClass SomeClass;
int SomeClass;

Тогда компилятор помечает определение int SomeClass как ошибку, как и должно быть.

7 голосов
/ 05 июня 2009

Смотрите этот предыдущий ответ на связанный вопрос. Это длинная цитата из статьи Дэна Сакса, которая объясняет эту проблему так же ясно, как и все, с чем я сталкивался:

Разница между 'struct' и 'typedef struct' в C ++?

Техника может предотвратить реальные проблемы (хотя, по общему признанию, редкие проблемы).

Это дешевая страховка - это нулевая стоимость во время выполнения или в пространстве кода (единственная стоимость - это несколько байтов в исходном файле), но получаемая вами защита настолько мала, что редко кто-то использует ее последовательно , У меня есть фрагмент «нового класса», который включает typedef, но если я на самом деле кодирую класс с нуля без использования фрагмента, я почти никогда не удосуживаюсь (или это помните?) Добавить typedef.

Так что я бы сказал, что я не согласен с большинством представленных здесь мнений - стоит добавить эти typedef, но недостаточно, чтобы я огорчил кого-либо (включая меня) из-за того, что не вставил их.

Меня попросили привести пример того, как отсутствие определения типа typedef может привести к неожиданному поведению - вот пример, более или менее взятый из статьи Saks:

#include <iostream>
#include <string>

using namespace std;

#if 0   // change to #if 1 to get different behavior
        // imagine that this is buried in some header
        // and even worse - it gets added to a header 
        //     during maintenance...
string foo()
{
    return "function foo... \n";
}
#endif

class foo
{
public:
    operator string() {
        return "class foo...\n";
    }
};

int main()
{
    string s = foo();

    printf( "%s\n", s.c_str());
    return 0;
}

Когда объявление функции становится видимым, поведение программы незаметно меняется, поскольку между функцией foo и классом foo.

нет конфликта имен.

Однако, если вы включите «typedef class foo foo;», вы получите ошибку времени компиляции вместо тихой разницы в поведении.

6 голосов
/ 05 июня 2009

Адам предоставил правильную причину для этого, но в отношении вашего вопроса «Стоит ли это хлопот», я бы сказал решительное «Нет!». Код возможной проблемы:

class SomeClass { ... };
int SomeClass;

будет пойман, когда чуть позже кто-то скажет:

SomeClass sc;

По общему признанию, компилятор будет указывать на "неправильную" строку, но такого рода вещи случаются настолько редко (я не думаю, что я когда-либо видел это в реальном коде), что это не может оправдать лес почти лишнего Определения типов.

0 голосов
/ 05 июня 2009

Либо действительно сломанный компилятор, либо кто-то, не зная, что они делают, или я так думаю.

0 голосов
/ 05 июня 2009

Мне кажется, что ваш коллега, возможно, еще не окончил C.

В C, если вы объявляете struct foo {int a;};, у вас нет ничего, что вы могли бы назвать просто foo, а скорее struct foo. Поэтому довольно часто для typedef struct foo используется foo.

Это было изменено в C ++ по причинам, которые должны быть довольно очевидными.

0 голосов
/ 05 июня 2009

Я понимаю концепцию различные пространства имен, теги и идентификаторы живут в, но это действительно даже стоит потратить печатать это?

номер

0 голосов
/ 05 июня 2009

Похоже, что комментарий пытается сказать, что typedef делает символ SomeClass глобальным таким образом, чтобы никто не смог объявить локальный объект с тем же именем, которое скрывает исходный SomeClass.

Я попробовал это с VC6 (не настоящий компилятор C ++, который я знаю, но лучший у меня есть ATM), и, похоже, он мало что делает. SomeClass все еще скрывается локальной декларацией с тем же именем. Возможно, он изменяет содержимое сообщения об ошибке для некоторого компилятора, чтобы сделать его более полезным.

...