Урок №60. Псевдонимы типов: typedef и type alias

  Юрий  | 

  |

  Обновл. 13 Сен 2021  | 

 109452

 ǀ   18 

На этом уроке мы рассмотрим псевдонимы типов typedef и type alias в языке C++.

typedef

Ключевое слово typedef позволяет программисту создать псевдоним для любого типа данных и использовать его вместо фактического имени типа. Чтобы объявить typedef (использовать псевдоним типа) — используйте ключевое слово typedef вместе с типом данных, для которого создается псевдоним, а затем, собственно, сам псевдоним. Например:

Обычно к псевдонимам typedef добавляют окончание _t, указывая, таким образом, что идентификатором является тип, а не переменная.

typedef не определяет новый тип данных. Это просто псевдоним (другое имя) для уже существующего типа. Его можно использовать везде, где используется обычный тип.

Даже если следующее не имеет смысла, оно все равно разрешено в языке C++:

typedef и читабельность кода


typedef используется в улучшении документации и разборчивости кода. Имена таких типов, как char, int, long, double и bool хороши для описания того, какой тип возвращает функция, но чаще всего мы хотим знать, с какой целью возвращается значение. Например, рассмотрим следующую функцию:

Мы видим, что возвращаемым значением является целое число, но что оно означает? Количество пропущенных вопросов? Идентификационный номер учащегося? Код ошибки? Сам int ни о чем нам не говорит. Исправим ситуацию:

С использованием возвращаемого типа testScore_t становится очевидным, что функция возвращает тип, значением которого является результат теста.

typedef и поддержка кода

typedef также позволяет изменить базовый тип объекта без внесения изменений в большое количество кода. Например, если вы использовали тип short для хранения идентификационного номера учащегося, но потом решили, что лучше использовать тип long, то вам придется прошерстить кучу кода для замены short на long. И, вероятно, было бы трудно определить, какой из типов short используется для хранения идентификационных номеров, а какой — для других целей.

С typedef же всё, что вам нужно сделать, — это изменить объявление typedef short studentID_t на typedef long studentID_t. Тем не менее, не стоит забывать об осторожности при изменении типа typedef на тип из другого семейства (например, из int на float или наоборот)! Новый тип данных может иметь проблемы со сравнением или делением целых чисел/чисел типа с плавающей точкой, которых старый тип не имел — об этом следует помнить.

typedef и кроссплатформенность


Еще одним большим преимуществом typedef является возможность скрывать специфические для определенных платформ (операционных систем) детали. На некоторых платформах тип int занимает 2 байта, на других — 4 байта. Таким образом, использование типа int для хранения более 2 байтов информации может быть потенциально опасным при написании кроссплатформенного кода.

Поскольку char, short, int и long не указывают свой размер, то для кроссплатформенных программ довольно часто используется typedef для определения псевдонимов, которые включают размер типа данных в битах. Например, int8_t — это 8-битный signed int, int16_t — это 16-битный signed int, а int32_t — это 32-битный signed int.

typedef и упрощение сложного

Хотя мы до сих пор рассматривали только простые типы данных, в языке C++ вы можете увидеть и следующие переменные/функции:

Писать std::vector<std::pair<std::string, int>> всякий раз, когда нужно использовать этот тип — не очень эффективно и затратно как по времени, так и по приложенным усилиям. Гораздо проще использовать typedef:

Вот! Другое дело! Ведь проще использовать pairlist_t вместо std::vector<std::pair<std::string, int>>, не так ли?

Не переживайте, если вы еще не знаете, что такое std::vector, std::pair и прочее. Гораздо важнее сейчас усвоить, что с помощью typedef вы можете давать простые имена сложным типам данных, что сделает их проще как для использования, так и для понимания.

type alias


У typedef есть также свои нюансы. Во-первых, легко забыть, что пишется первым: псевдоним типа или имя типа:

Во-вторых, синтаксис typedef становится уже менее привлекательным в связке со сложными типами данных (об этом мы поговорим детально, когда будем рассматривать указатели на функции).

Для решения этих проблем, в C++11 ввели новый улучшенный синтаксис для typedef, который имитирует способ объявления переменных. Этот синтаксис называется type alias. С помощью type alias мы пишем имя, которое затем используется как синоним конкретного типа данных (т.е. принцип тот же, но синтаксис более удобен).

Следующий typedef:

В С++11 можно объявить как:

Эти два способа функционально эквивалентны.

Обратите внимание, что хоть мы и используем ключевое слово using, оно не имеет ничего общего с using-стейтментами. Это ключевое слово имеет различный функционал в зависимости от контекста.

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

Правило: Используйте type alias вместо typedef, если ваш компилятор поддерживает C++11.

Тест

Задание №1

Используя следующий прототип функции:

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

Ответ №1

Задание №2

Используя прототип функции из задания №1, преобразуйте тип возвращаемого значения int в status_t, используя ключевое слово using (C++11). В ответе к этому заданию укажите стейтмент создания псевдонима типа и обновленный прототип функции.

Ответ №2

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (498 оценок, среднее: 4,94 из 5)
Загрузка...

Комментариев: 18

  1. Павел:

    Несколько интересных моментов по работе с IDE:

    Если навести курсор на псевдоним — Visual Studio даст подсказку-расшифровку из чего он сделан.

    Если нажать на него с Ctrl — откроется файл, в котором этот псевдоним определен.

    Если нажать на псевдоним и потом нажать F1 — откроется страница с документацией.

    Это работает не только с псевдонимами — полезно экспериментировать!

  2. Георгий:

    Что то я не понял про typedef в кроссплатформенности? Почему он помогает? Разве я не могу просто без него типы данных int8_t написать?

    Можно объяснить?)

    1. Fantasy:

      Тут по глупому просто. Как и в предыдущем примере они имеют в виду что если ты хочешь портануть программу на другое ОП то тебе всего лишь нужно будет заменить одну строчку а не шерстить по всему коду.

  3. Руслан:

    Здравствуйте! Вопрос про typedef и кроссплатформенность. В уроке №32 «Фиксированный размер целочисленных типов данных», говорилось чтобы решить вопрос кроссплатформенности, в язык С++ добавили набор целочисленных типов фиксированного размера, которые гарантированно имеют один и тот же размер на любой архитектуре (#include <cstdint>). В этом уроке говорится что можно использовать псевдоним, например, int8_t — это 8-битный signed int. Как видится мне в этом случае за размером типа данных, вернее за его наполнением, придется следить самому программисту. При этом псевдоним int8_t и т.п. совпадает с названием целочисленного типа фиксированного размера (что при подключенной библиотеке <cstdint> потенциально может привести к конфликту имён).
    Что целесообразнее ( и (или) безопаснее) использовать для обеспечения кроссплатформенности псевдоним типа или целочисленный тип фиксированного размера?

    1. Томас:

      Да, использование определения типа в качестве псевдонима действительно выдаст конфликт имён, это нетрудно проверить.
      А всё потому что в уроке имелось в виду, что за псевдонимом можно скрыть определение фиксированного типа, а не использовать определение фиксированного типа как псевдоним.

  4. Ya:

    Поясните пожалуйста мне, недалекому, что в этой строке происходит.

    1. Алексей:

      Это вектор пар вида (строка, число)

    2. Демьян:

      Раскройте скобки постепенно, начните с правой части. Мы хотим создать пару строка-число, затем вектор (этакий продвинутый список) получает уже эту пару в качестве элементов

  5. Алексей:

    Тесты на ура пошли.

    Елки-палки, наворотить можно, но с опытом с этим научись работать и будет тебе счастье.

    Оптимизация и работоспособность — цель всех активностей в создании чего либо.

    Спасибо за курс, хочу до конца изучить, for sure!

  6. Алексей:

    А что тут переживать. Я знаю, что много не знаю по с++.
    Я вижу, что простые вещи понять и принять — буду через пол года писать, то что в снах не присниться и это будет оптимизировано, работать, работать быстро.

    К чему всегда и стремлюсь.

  7. deb:

    Очень крутой понятный урок.

    1. Фото аватара Юрий:

      Пасиб 🙂

  8. Геннадий:

    Цель программиста- выразить вычисления, причем это должно быть сделано:
    -правильно;
    -просто;
    -эффективно.
    (Бьярне Страуструп. "Программирование". Второе издание. стр.156)

  9. benya:

    Зачем нужен typedef, когда мы можем того же достичь с помощью define?

    1. Tosha:

      typedef имеет контекст и не конфликтует с другими именами в коде. Например typedef int a; a a = 1; — вполне корректная запись, хоть и извращенная. В объявлении переменной первый идентификатор является ее типом, а второй — именем. Используя макросы, мы бы переписали и тип переменной, и ее имя, что завершилось бы ошибкой компиляции.
      Разумеется, подобное использовать не стоит, я просто попытался показать, что typedef дает больше возможностей. Другой пример — ты можешь использовать в разных пространствах имен одно и то же имя для псевдонима разных типов, более точно отображая смысл своего кода.

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

  10. kmish:

    Добрый день, все понятно и прозрачно.
    Но есть небольшое субъективное замечание, которое мне видится.

    Разве имя функции не должно объяснять, что она возвращает (как Вы ранее писали в одном из уроков)?
    В данном случае, делая псевдоним еще и для типа, получается избыточность. По функции итак отлично понятно, что она результат теста дает и int тут вполне уместен.

    1. Руслан:

      int, да уместен, а вот " std::vector<std::pair<std::string, int> " ну триндец как не уместен и порой возможно не понятен. И слава tepedef, что можно просто написать вместо:

      и вместо гемороя выше, подкоректировать в:

      что бы стало красивым и читабельным:

      1. Артемий:

        Просто продолжай читать…

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *