2010-12-27 4 views
6

Мое понимание typedef - дать объявление псевдонимам. Такое объявление для int теперь будет называться Integer. Но почему? Почему кто-то использует typedef? Какая более выгодная причина?Зачем использовать C++ Typedef?

typedef int Integer; 

Integer blamo = 50; 

cout << blamo << endl; 
+0

Возможный дубликат [C++ typedef question ... easy one ..] (http://stackoverflow.com/questions/1664028/c-typedef-question-easy-one) – marcog

ответ

18

, что не является хорошим примером, потому что Integer и int не имеют различное значение. Но представьте себе, что-то подобное,

typedef int BlamoType; 

Теперь, в будущем, когда «blamo» становится 64-разрядным целым числом, вы можете просто изменить ЬурейиЙ, а весь остальной код остается неизменным.

Другая причина для typedef заключается в сокращении имен типов. Например, вместо

boost::shared_ptr<std::map<std::wstring, std::vector<int> > > blamo1; 
boost::shared_ptr<std::map<std::wstring, std::vector<int> > > blamo2; 
std::vector<boost::shared_ptr<std::map<std::wstring, std::vector<int> > > > blamoList; 

вы можете сделать:

typedef boost::shared_ptr<std::map<std::wstring, std::vector<int> > > BlamoType; 
BlamoType blamo1; 
BlamoType blamo2; 
std::vector<BlamoType> blamoList; 
+1

Это также отличный пример проблема с typedefs: «в будущем, когда« blamo »станет 64-битным целым». Когда мой код ломается, потому что кто-то изменил тип, который я не вижу, не отслеживая определение. – Jay

+3

Jay: как это отличается от изменения внутренних компонентов обычного класса? – phlip

+3

@Jay это не проблема с какой-либо инкапсуляцией? Вы против инкапсуляции? – tenfour

7

Таким образом, вы должны ввести только boost::shared_ptr<std::map<std::string,std::string>> один раз?

+0

Ответ tenfour связан и лучше объясняется. typedef позволяет абстрагироваться от деталей типа и придавать ему значимое имя. Это немного похоже на завершение интерфейса интерфейсом, но проще. Недостатком является безопасность типа - два typedefs, указывающие на один и тот же класс, действительно одно и то же, даже если вы имели в виду, что они были разными. У вас может быть typedef double Time; typedef double Money; а затем назначить время на деньги. – phlip

2

The power of 'typedef' in C++ говорит:

C++ позволяет определить наши собственные типов на основе других существующих данных типов. Мы можем сделать это, используя ключевое слово typedef , формат которого:

typedef existing_type new_type_name;

где existing_type является C++ фундаментальный или тип соединения и new_type_name это имя для нового типа мы определяем.

Например:

typedef char C; 
typedef unsigned int WORD; 
typedef char * pChar; 
typedef char field [50]; 

Some more detail about typedef Specifier


+1

7.1.3 [dcl.typedef] говорит, что 'typedef-name является синонимом другого типа', поэтому вы не можете определить свой собственный тип, вы можете просто псевдоним другого типа. Это важное различие, потому что, хотя псевдонимы могут быть «конвертированы» (даже не это) в другие псевдонимы, которые имеют одно и то же определение, новые типы по умолчанию не могут быть преобразованы в другие типы. Язык программирования D's 'typedef' действительно вводит новые типы, и он имеет' alias' для 'typedef' в C++. Реальные typedefs интересны для списков аргументов функций типов (думаю, 'Angle (degree (10))', но псевдонимы C++ не являются. –

+0

Я склонен думать, что это определение того, как работы typedef заканчиваются запутыванием, когда вы смотрите на такие вещи, как typedefs указателей функций.Не даже это, хотя, когда вы смотрите на определение, а затем смотрите на массив typedef, он выглядит не так. Когда я наконец понял, что вы пишете определение как обычно, но используйте новое имя типа на месте от имени переменной, а затем добавить typedef, мне стало намного понятнее. – Firedragon

0

Другие примеры, где было бы разумным, заключалось в том, чтобы иметь краткое сокращение для типа данных, которое было реализовано как указатель на структуру, скажем.

2

C++ имеет очень сложную систему типов, и некоторые типы могут быть очень сложными для выражения. typedef уменьшает количество необходимого кода. Typedef также позволяет пользователю изолироваться от изменений типа и, наконец, позволяет пользователям соответствовать интерфейсам с полукомпилированным временем, например, определять тип итератора.

4

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

int Search(void* key, void* array, int len, int (*someFunc)(void*, void*)) 
{ 
    // do stuff, call passed in function, etc. 
} 

я предпочел бы сделать это таким образом

typedef int (*ComparisonFunc)(void*, void*) 

int Search(void* key, void* array, int len, ComparisonFunc fn) 
{ 
    // do stuff, call passed in function, etc. 
} 

прощают функцию сравнения C здесь, концепция применима в C++, а также (но не будет выполнять дженерики в терминах указателей аннулированию конечно)

3

Ну, это не значит, что имя более подробно.

Существует три основные причины.

Первый, чтобы сделать имя менее подробным & проще набрать. Это преимущество часто возникает при игре с классами и/или шаблонами. Например, если у вас есть map между а string и какой-либо объект, используя ЬурейеЕ может помочь за счет сокращения конструкций, как это:

for(std::map<string, MyObj>::iterator it = my_map_.begin(); it != my_map_.end(); ++it) 

к этому:

typedef std::map<string, MyObj> MyMap; 
for(MyMap::iterator it = my_map_.begin(); it != my_map_.end(); ++it) 

Полезность пропорционально тому, как часто вам нужно объявить что-то типа MyObjMap. Только раз? Не очень полезно. Тысячи раз? Довольно полезно. Это также помогает сделать код более ясным & самодокументирующимся, особенно когда вы объявляете много объектов этих типов.

Вторая причина также может быть причиной отказа. Это делается, чтобы попытаться получить определенный уровень рождаемости и расширяемости. Это делается особенно для типов членов класса. Идея состоит в том, чтобы сделать ваши классы более универсальными, чтобы при изменении типов членов вам не нужно было изменять код вызова. Но я упоминаю, что это также может быть противозаконным, потому что люди часто думают, что это имеет гораздо большую выгоду, чем на самом деле. Передумать. Как часто у вас действительно меняет тип члена от, скажем, __int32 до __int64? Может быть, пару раз? Это действительно достаточно, чтобы установить шаблон кодирования?

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

+2

Я должен не согласиться с «Это также помогает сделать код более понятным и самодокументированным». Когда я получаю код, объявляющий переменные с помощью typedef, t знаю, что такое переменная. «ValueType x;» легче вводить, но ничего не говорит о типе. – Jay

+2

@Jay: Если вам нужно знать базовый тип, то я согласен. Это не всегда * * Полезно, но во многих случаях , если класс хорошо разработан, вам может не понадобиться знать базовый тип. –

11

Причина, по которой никто не упомянул здесь: написать общий код. Рассмотрим реализацию некоторого контейнера, например std::vector. Он должен иметь тип с именем std::vector<T>::value_type поэтому все, кто пишет универсальный код может использовать его:

template<class Container> void f(const Container &c) 
{ 
    typename Container::value_type v = c.back(); 
    // ... 
} 

Как можно ввести такой тип в вашем классе?Единственный способ это ЬурейиЙ:

// !!!EXPOSITION ONLY!!! 
template<class T> class vector 
{ 
public: 
    typedef T value_type; 
    // ... 
}; 
3

Есть по крайней мере 3 причина, почему я использую определения типов, наиболее/все из которых были охвачены в ответах уже:

- упрощение:

typedef int (*funcptr)(char, unsigned long); 
funcptr f; // f is a ptr to a function taking char & unsigned long, returning an int 

typedef std::vector<Record> Container; 
Container c; // c is a vector of Records 

- инкапсуляция:

typedef unsigned short int MY_COUNTER; 
MY_COUNTER c; 

Теперь, если позже, я хочу сделать MY_COUNTER больше, я просто изменяю typedef и обновляется весь встречный код (после перекомпиляции). Обратите внимание: если бы я использовал unsigned short int явно везде для счетчика, мне пришлось бы просматривать все файлы и менять только unsigned short int для счетчика; Я не могу просто глобально заменить unsigned short int во всем коде, потому что я мог бы использовать его для других вещей, кроме счетчика.

- портативность

typedef unsigned short UINT16; 

Теперь, когда я иду на другую платформу, я просто карта UINT16 к чему-то еще (например, unsigned long) в одном месте (заголовочный файл), но все мой код все еще работает (после перекомпиляции). Почти как «брандмауэр типа» - он предотвращает распространение изменений платформы во всех кодах. Любой разработчик (особенно встроенные разработчики, которые всегда используют w/code на нескольких архитектурах &), которым когда-либо приходилось проходить через большую кодовую базу C или C++ &, меняют все вхождения int на short int или что бы это ни было связано с этим.

Обратите внимание, что для любого недавнего компилятором, использованиеstdint.hчасто доступны & лучший способ приблизиться к платформе портативность. Но я работаю над многими системами, где компилятор старше &stdint.hне существует (или его необходимо создать).


Есть много других хорошие применения для определений типов, особенно, как вы делаете больше работы с шаблонами, но эти 3 ситуаций являются одними из наиболее распространенных, полезных и интуитивных/очевидных применений (по крайней мере, ИМО).

+0

Отличный ответ, очень недооцененный! – Konstantin

Смежные вопросы