Правильное использование typedef в C ++

.equals() сравнивает данные в классе (при условии, что функция реализована). == сравнивает местоположения указателя (расположение объекта в памяти).

== возвращает true, если оба объекта (NOT TALKING OF PRIMITIVES) указывают на экземпляр SAME. .equals() возвращает true, если два объекта содержат одни и те же данные equals() Versus == в Java

Это может вам помочь.

13
задан Community 23 May 2017 в 11:45
поделиться

12 ответов

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

Ваша неприязнь к ним, когда дело доходит до их поиска, значительно уменьшается при работе с IDE, поскольку я могу просто навести курсор на имя типа, и IDE сообщает мне, как он определяется.

Более полезные ситуации возникают, когда у вас есть вложенные контейнеры - вы можете дать именам некоторое семантическое значение, не определяя целые классы:

typedef std::list<Foobar> FoobarList;
typedef std::map <string, FoobarList> GizmosToFoobarsMap;

Вы также можете сэкономить МНОГО печатания при работе с итераторами этих типов (хотя это уменьшено теперь, когда C ++ 0x имеет auto .)

18
ответ дан 1 December 2019 в 17:47
поделиться

typedef важны для STL и программирования шаблонов в целом. Просто посмотрите, как работают черты итератора:

template <class Iterator>
struct iterator_traits {
  typedef typename Iterator::iterator_category iterator_category;
  typedef typename Iterator::value_type        value_type;
  typedef typename Iterator::difference_type   difference_type;
  typedef typename Iterator::pointer           pointer;
  typedef typename Iterator::reference         reference;
};

template <class T>
struct iterator_traits<T*> {
  typedef random_access_iterator_tag iterator_category;
  typedef T                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef T*                         pointer;
  typedef T&                         reference;
};

Что касается «сокращенного» использования typedef s - я думаю, что это прекрасно, когда оно локализовано в файле реализации. У меня здесь то же правило, что и для с использованием пространства имен - если это избавляет меня от набора текста и не сбивает с толку других, действуйте.

9
ответ дан 1 December 2019 в 17:47
поделиться

Мне нравятся такие определения типов, потому что они улучшают читаемость. Рассмотрите возможность использования std :: vector :: const_iterator повсюду или даже std :: map > :: итератор . Половина вашего кода заканчивается просто описанием типов, и набор определений типов значительно упрощает это. Я не думаю, что это слишком сложно для понимания - IDE обычно могут сказать вам тип, если вы наводите на него указатель мыши или переходите к определению, а работа с кодом обычно требует, чтобы вы все равно понимали такие вещи.

7
ответ дан 1 December 2019 в 17:47
поделиться

Мне нравится этот typedef , потому что он позволяет изменить тип контейнера позже (скажем, профилирование показало, что std :: deque быстрее, чем std :: list ) , без изменения всего рассматриваемого кода .

И на случай, если вы задаетесь вопросом: я не возражаю против того, чтобы то, что называется списком, даже если это может быть std :: deque . В этом контексте я рассматриваю «список» как концептуальный термин, а не как структуру данных. (Вы ведь не составляете списки покупок как двусвязные?)

5
ответ дан 1 December 2019 в 17:47
поделиться

Я лично считаю, что определения типов очень полезны при работе с шаблонным кодом, как при написании шаблонов, так и при их создании.

Написание шаблонов:

typedef требуется для метапрограммирования шаблонов. Например, удаление const:

template<typename T>
struct RemoveConst
{
typedef T Type;
};

template<>
struct RemoveConst<const T>
{
typedef T Type;
};

Теперь мы можем получить доступ к типу без констант из любого T путем создания экземпляра RemoveConst :: Type

Создание экземпляров шаблонов:

Как и многое в программировании, правильный инструмент для правильного job. typedef, такой как ваш пример

typedef std::list<Foobar> FoobarList;
...
FoobarList GetFoobars();

Звучит вполне разумно, главным образом потому, что определенное типом имя является описательным (FoobarList - это список Foobars). Это очень полезно, особенно при работе с контейнерами STL или любыми другими типами шаблонов, которые используют один и тот же интерфейс. представьте себе следующее объявление класса:

class SomeClass
{
...
std::vector<int> mContainer;
};

Этот класс, вероятно, будет перебирать элементы контейнера, что приведет к получению кода, подобного:

for(std::vector<int>::iterator It = mContainer.begin(); It != mContainer.end(); ++It)
{
}

Теперь представьте, что вы понимаете, после написания вышеупомянутого цикла for 5 различными методами, что вы постоянно вставляете в середину массива, и что std :: list намного лучше подходит для этой работы. В этом случае вам придется пройти через все экземпляры std :: vector :: iterator и измените объявление.

Вместо этого вы можете определить тип контейнера, который вы используете внутри класса:

class SomeClass
{
typedef std::vector<int> IntContainer;
...
IntContainer mContainer;
};

Это может позволить вам написать очень общий код, который можно очень легко изменить.

for(IntContainer::iterator It = mContainer.begin(); It != mContainer.end(); ++It)
{
}

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

1
ответ дан 1 December 2019 в 17:47
поделиться

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

0
ответ дан 1 December 2019 в 17:47
поделиться

Я думаю, что в этом случае хорошей практикой является typedef. Хотя синтаксис шаблона ставит параметры перед вами, обычно они представляют собой те вещи, которые можно попытаться инкапсулировать в объектно-ориентированной среде.

typedef'ing шаблона выполняет эту инкапсуляцию.

0
ответ дан 1 December 2019 в 17:47
поделиться

В вашем примере FoobarList не отличается от любого другого класса; вам все равно придется посмотреть определение или документацию, чтобы знать, как его использовать; и вы не стали бы использовать это как аргумент в пользу отказа от классов!

В этом случае, как только вы определили, что это STL std :: list, вы будете знать, как его использовать или, по крайней мере, где найти документацию хорошего качества; что, вероятно, больше, чем вы можете сказать для большинства классов, которые могут быть определены в вашем проекте.

При этом я неоднозначно отношусь к тому, хорошая это идея или нет; Я просто считаю, что это в основном безвредно.

2
ответ дан 1 December 2019 в 17:47
поделиться

Лично я также typedef материал STL, список и итератор ( Foos и FooIterator ). Используемый повсюду создает очень четкий (imo) стиль, к которому вы привыкаете ко второму случаю.

Кроме того, вы можете просто навести указатель мыши на тип, чтобы увидеть, что он на самом деле означает в любой реальной среде IDE (vs или eclipse), так что у вас будет вся необходимая информация прямо в момент ее использования в дополнение к тому, что вам не нужно прокручивать 3 экрана. вправо, чтобы прочитать всю строку.

С ключевым словом C ++ 0x auto это больше не понадобится. Да, я верю в ключевое слово C # var , и снова вы можете навести на него курсор, чтобы увидеть тип, если сомневаетесь!

3
ответ дан 1 December 2019 в 17:47
поделиться

Я тоже не делаю этого в своем коде, так что, думаю, вы не одиноки. На мой взгляд, это заставляет читателя искать еще одну вещь. У плохого читателя кода их уже более чем достаточно.

2
ответ дан 1 December 2019 в 17:47
поделиться

Если я хочу, чтобы конечный тип был строго типизирован, я обычно предпочитаю наследование, а не typedef , например, class CMyMap: public CMap {...}

Таким образом, CMyMap строго типизирован - я просто не могу передать CMap в метод, который принимает CMyMap в качестве параметра. typedef просто сообщает компилятору «другое имя для», но определение класса определяет новый тип.

Если я определил функцию void foo (const CMyMap & map);

, но я использовал typedef для определения CMyMap, например typdef CMap CMyMap; тогда кто-то может сделать CMap myMap; foo (myMap); и компилятор быть вполне счастливым.

Но если я действительно хочу, чтобы foo был строго типизирован и использовал ТОЛЬКО CMyMap, то для «типизации» я предпочитаю наследование.

Кстати, CMyMap является своего рода общим, но более конкретным может быть CPhoneNumber2Index, где номер телефона представлен целым числом, а индекс - целым числом. Здесь очевидно, что мой CPhoneNumber2Index - это не просто отображение целого числа на другое целое число. Таким образом, foo может быть строкой ReverseLookup (const CPhoneNumber2Index & PhoneBook, int iPhoneNumber); , что показывает, что ReverseLookup имеет какое-то отношение к телефонным номерам, а не CMap

0
ответ дан 1 December 2019 в 17:47
поделиться

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

0
ответ дан 1 December 2019 в 17:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: