Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

(T)v

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

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

reinterpret_cast<int*>(7) */

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

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

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

S1 a;

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

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

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

reinterpret_cast<S1*>(&a) */

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

const_cast<S2*>(&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
, но сделает эти ужасные операции заметными и привлечет внимание программиста.

27.3.5. Преобразование указателей типа void*

В языке указатель типа

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++.

  • Читать дальше
  • 1
  • ...
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: