Читаем Программирование. Принципы и практика использования C++ Исправленное издание полностью

  Это так называемое “приведение в стиле языка С”, или “приведение в старом стиле”. Его любят люди, не умеющие набирать тексты (за лаконичность) и ленивые (потому что они не обязаны знать, что нужно для того, чтобы из переменной v получилась переменная типа T). С другой стороны, этот стиль яростно отвергают программисты, занимающиеся сопровождением программ, поскольку такие преобразования остаются практически незаметными и никак не привлекают к себе внимания. Приведения в языке С++ (приведения в новом стиле (new-style casts), или приведения в шаблонном стиле (template-style casts); см. раздел А.5.7) осуществляют явное преобразование типов, которое легко заметить. В языке С у вас нет выбора.

int* p = (int*)7;   /* интерпретирует битовую комбинацию:

                       reinterpret_cast(7) */

int x = (int)7.5;   /* усекает переменную типа: static_cast(7.5) */

typedef struct S1 { /* ... */ } S1;

typedef struct S2 { /* ... */ } S2;

S1 a;

const S2 b;         /* в языке С допускаются неинициализированные

                    /* константы */

S1* p = (S2*)&a    /* интерпретирует битовую комбинацию:

                       reinterpret_cast(&a) */

S2* q = (S2*)&b    /* отбрасывает спецификатор const:

                       const_cast(&b) */

S1* r = (S1*)&b    /* удаляет спецификатор const и изменяет тип;

                       похоже на ошибку */

Мы не рекомендуем использовать макросы даже в программах на языке C (раздел 27.8), но, возможно, описанные выше идеи можно было бы выразить следующим образом:

#define REINTERPRET_CAST(T,v) ((T)(v))

#define CONST_CAST(T,v) ((T)(v))

S1* p = REINTERPRET_CAST (S1*,&a);

S2* q = CONST_CAST(S2*,&b);

Это не обеспечит проверку типов при выполнении операторов reinterpret_cast и const_cast, но сделает эти ужасные операции заметными и привлечет внимание программиста. 

<p id="AutBody_Root547"><strong>27.3.5. Преобразование указателей типа void*</strong></p>

В языке указатель типа void* можно использовать как в правой части оператора присваивания, так и для инициализации указателей любого типа; в языке C++ это невозможно. Рассмотрим пример.

void* alloc(size_t x); /* выделяет x байтов */

void f (int n)

{

  int* p = alloc(n*sizeof(int)); /* OK в языке C;

                                    ошибка в языке C++ */

  /* ... */

}

Здесь указатель типа void* возвращается как результат функции alloc и неявно преобразовывается в указатель типа int*. В языке C++ мы могли бы переписать эту строку следующим образом:

int* p = (int*)alloc(n*sizeof(int)); /* OK и в языке C,

                                        и в языке C++ */

Мы использовали приведение в стиле языка C (раздел 27.3.4), чтобы оно оказалось допустимым как в программах на языке C, так и в программах на языке C++.

  Почему неявное преобразование void* в T* является недопустимым в языке С++? Потому, что такие преобразования могут быть небезопасными.

void f

{

  char i = 0;

  char j = 0;

  char* p = &i

  void* q = p;

  int* pp = q; /* небезопасно; разрешено в языке C,

                  ошибка в языке C++ */

  *pp = –1;    /* перезаписываем память, начиная с адреса &i */

В данном случае мы даже не уверены, какой фрагмент памяти будет перезаписан: переменная j или часть памяти, на которую ссылается указатель p? А может быть, память, использованная для управлении вызовом функции f (стек функции f)? Какие бы данные ни были перезаписаны, вызов функции f приведет к печальным последствиям.

Обратите внимание на то, что (обратное) преобразование указателя типа T* в указатель типа void* является совершенно безопасным, — вы не сможете придумать ужасные примеры, подобные предыдущему, — и они допускаются как в языке C, так и в языке C++.

К сожалению, неявное преобразование void* в T* широко распространено в языке C и, вероятно, является основной проблемой совместимости языков С и С++ в реальных программах (см. раздел 27.4).

<p id="AutBody_Root548"><strong>27.3.6. Перечисление</strong></p>

В языке C можно присваивать целое число перечислению без приведения int в enum. Рассмотрим пример.

enum color { red, blue, green };

Перейти на страницу:

Похожие книги

97 этюдов для архитекторов программных систем
97 этюдов для архитекторов программных систем

Успешная карьера архитектора программного обеспечения требует хорошего владения как технической, так и деловой сторонами вопросов, связанных с проектированием архитектуры. В этой необычной книге ведущие архитекторы ПО со всего света обсуждают важные принципы разработки, выходящие далеко за пределы чисто технических вопросов.?Архитектор ПО выполняет роль посредника между командой разработчиков и бизнес-руководством компании, поэтому чтобы добиться успеха в этой профессии, необходимо не только овладеть различными технологиями, но и обеспечить работу над проектом в соответствии с бизнес-целями. В книге более 50 архитекторов рассказывают о том, что считают самым важным в своей работе, дают советы, как организовать общение с другими участниками проекта, как снизить сложность архитектуры, как оказывать поддержку разработчикам. Они щедро делятся множеством полезных идей и приемов, которые вынесли из своего многолетнего опыта. Авторы надеются, что книга станет источником вдохновения и руководством к действию для многих профессиональных программистов.

Билл де Ора , Майкл Хайгард , Нил Форд

Программирование, программы, базы данных / Базы данных / Программирование / Книги по IT
Программирование. Принципы и практика использования C++ Исправленное издание
Программирование. Принципы и практика использования C++ Исправленное издание

Специальное издание самой читаемой и содержащей наиболее достоверные сведения книги по C++. Книга написана Бьярне Страуструпом — автором языка программирования C++ — и является каноническим изложением возможностей этого языка. Помимо подробного описания собственно языка, на страницах книги вы найдете доказавшие свою эффективность подходы к решению разнообразных задач проектирования и программирования. Многочисленные примеры демонстрируют как хороший стиль программирования на С-совместимом ядре C++, так и современный -ориентированный подход к созданию программных продуктов. Третье издание бестселлера было существенно переработано автором. Результатом этой переработки стала большая доступность книги для новичков. В то же время, текст обогатился сведениями и методиками программирования, которые могут оказаться полезными даже для многоопытных специалистов по C++. Не обойдены вниманием и нововведения языка: стандартная библиотека шаблонов (STL), пространства имен (namespaces), механизм идентификации типов во время выполнения (RTTI), явные приведения типов (cast-операторы) и другие. Настоящее специальное издание отличается от третьего добавлением двух новых приложений (посвященных локализации и безопасной обработке исключений средствами стандартной библиотеки), довольно многочисленными уточнениями в остальном тексте, а также исправлением множества опечаток. Книга адресована программистам, использующим в своей повседневной работе C++. Она также будет полезна преподавателям, студентам и всем, кто хочет ознакомиться с описанием языка «из первых рук».

Бьерн Страуструп , Бьёрн Страуструп , Валерий Федорович Альмухаметов , Ирина Сергеевна Козлова

Программирование, программы, базы данных / Базы данных / Программирование / Учебная и научная литература / Образование и наука / Книги по IT