Главная

Популярная публикация

Научная публикация

Случайная публикация

Обратная связь

ТОР 5 статей:

Методические подходы к анализу финансового состояния предприятия

Проблема периодизации русской литературы ХХ века. Краткая характеристика второй половины ХХ века

Ценовые и неценовые факторы

Характеристика шлифовальных кругов и ее маркировка

Служебные части речи. Предлог. Союз. Частицы

КАТЕГОРИИ:






Явное приведение типа




В языке C++ существует четыре разновидности приведения типа. Все четыре типа записываются в виде

xxx_cast<type_to>(expression_from)

Например:

y = static_cast<signed short>(65534); // будет присвоено -2

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

 

Static_cast

• Назначение: Приведение типа по обычным правилам, когда компилятор отказывается привести его автоматически (отличается от применяемого в Си (type_to)expression_from только тем, что с указателями на произвольные типа не работает, может применяться только для преобразования void * к другому указателю и для преобразования вниз по иерархии классов; для произвольных указателей применяется reinterpret_cast). Применяется:

o для вычислений в более широком числовом типе (например, для дробных вычислений с целыми числами);

o чтобы избавиться от предупреждения «Возможная потеря точности» при переводе в более узкий числовой тип;

o для указателей и ссылок при конвертации в родительский тип;

o для типов с конструкторами или операциями конвертации наподобие operator type_to;

o в шаблонах — компилятор уже при специализации шаблона решает, какие операции использовать;

o в операции?:, у которой then- и else-части должны иметь один тип.

• Ограничения на expression_from: нет.

• Ограничения на type_to: должен найтись способ преобразования в type_to.

• Производит ли код: в общем случае да.

• Возможные ошибки: относительно безопасно. Логические ошибки возможны, если привести в неправильный тип или вообще пропустить приведение, когда оно требуется. Не исключено, что после преобразования появится временный объект, который будет благополучно уничтожен вместе со всеми изменениями (большинство компиляторов на это выдают предупреждение).

// Возвращает процент попаданий.

double hitpercent(const int aHitCount, const int aShotCount)

{

if (aShotCount==0) return 0.0;

// Нам нужно дробное деление, а не целочисленное - поэтому переведём делимое и делитель в double

return static_cast<double>(aHitCount*100) / static_cast<double>(aShotCount);

}

 

string s = static_cast<string>("Hello!"); // аналогично string s = string("Hello!");

string s = (string)"Hello!"; // синтаксис Си тоже работает

string s = static_cast<string>(5); // не компилируется - нет подходящего конструктора

 

Dynamic_cast

• Назначение: Проводит преобразование типа, предварительно убедившись (с помощью RTTI), что объект expression_from в действительности является объектом типа type_to. Если нет: для указателей возвращает NULL, для ссылок устанавливает аварийную ситуацию std::bad_cast.

• Ограничения на expression_from: выражение должно быть ссылкой или указателем на объект с хотя бы одной виртуальной функцией.

• Ограничения на type_to: ссылка или указатель на дочерний по отношению к expression_from тип.

• Производит ли код: да.

• Возможные ошибки: относительно безопасно. Логические ошибки возможны, если подать аргумент, не имеющий тип type_to, в то время как код не приспособлен к этому.

 

Const_cast

• Назначение: Снятие/установка модификатора const или volatile.

• Ограничения на expression_from: ссылка или указатель.

• Ограничения на type_to: должен совпадать с типом expression_from с точностью до модификаторов const или volatile.

• Производит ли код: нет.

• Возможные ошибки: чревато попыткой изменить неизменный объект.

namespace

{

// Каждая загрузка DLL создаёт новый сегмент данных.

// Так что с такими глобальными переменными одна программа не будет

// мешать другой.

string s = "Wikipedia";

}

 

typedef char* PChar;

 

// Функция экспортируется DLL'ем и возвращает какую-то строку

// в виде char*. Проблема в том, что std::string::c_str() возвращает

// const char*.

void __declspec(dllexport) WINAPI SomeDllFunction(PChar& rMessage)

{

rMessage = const_cast<char*>(s.c_str());

}

 

Reinterpret_cast

• Назначение: Участок памяти рассматривается как объект другого типа.

• Ограничения на expression_from: порядковый тип (логический, символьный, целый, перечисляемый), указатель, ссылка.

• Ограничения на type_to: для порядкового типа или указателя — порядковый тип или указатель. Для ссылки — ссылка.

• Производит ли код: нет.

• Возможные ошибки: Участок в реальности может и не иметь этого типа. Нет никакой возможности проверить это, всю ответственность за корректность преобразования программист берёт на себя.

// Возвращает true, если число конечное, и false - если бесконечное или NaN.

bool isfinite(const double x)

{

const uint64_t &y = reinterpret_cast<const uint64_t&>(x);

return ((y & UINT64_C(0x7FF0000000000000))!= UINT64_C(0x7FF0000000000000));

}

 

// Ошибка - выражение x+5.0 не является ссылкой.

const long long& y = reinterpret_cast<const long long&>(x+5.0);

 

 

Оператор sizeof.

Оператор sizeof возвращает размер в байтах объекта или типа данных. Синтаксис его таков:

sizeof (type name);

sizeof (object);

sizeof object;

Результат имеет специальный тип size_t, который определен как typedef в заголовочном файле cstddef. Вот пример использования обеих форм оператора sizeof:

#include <cstddef>

int ia[] = { 0, 1, 2 };

// sizeof возвращает размер всего массива

size_t array_size = sizeof ia;

// sizeof возвращает размер типа int

size_t element_size = array_size / sizeof(int);

Применение sizeof к массиву дает количество байтов, занимаемых массивом, а не количество его элементов и не размер в байтах каждого из них. Так, например, в системах, где int хранится в 4 байтах, значением array_size будет 12. Применение sizeof к указателю дает размер самого указателя, а не объекта, на который он указывает:

int *pi = new int[ 3 ];

size_t pointer_size = sizeof (pi);

Здесь значением pointer_size будет память под указатель в байтах (4 в 32-битных системах), а не массива ia.

Вот пример программы, использующей оператор sizeof:

#include <string>

#include <iostream>

#include <cstddef>

int main() {

size_t ia;

ia = sizeof(ia); // правильно

ia = sizeof ia; // правильно

// ia = sizeof int; // ошибка

ia = sizeof(int); // правильно

int *pi = new int[ 12 ];

cout << "pi: " << sizeof(pi)

<< " *pi: " << sizeof(pi)

<< endl;

 

// sizeof строки не зависит от

// ее реальной длины

string stl("foobar");

 

string st2("a mighty oak");

string *ps = &stl;

cout << " st1: " << sizeof(st1)

<< " st2: " << sizeof(st2)

<< " ps: sizeof(ps)

<< " *ps: " << sizeof(*ps)

<< endl;

 

cout << "short:\t" << sizeof(short) << endl;

cout << "shorf":\t" << sizeof(short*) << endl;

cout << "short&:\t" << sizeof(short&) << endl;

cout << "short[3]:\t" << sizeof(short[3]) << endl;

}

Результатом работы программы будет:

pi: 4 *pi: 4

st1: 12 st2: 12 ps: 4 *ps:12

short: 2

short*: 4

short&: 2

short[3]: 6

Из данного примера видно, что применение sizeof к указателю позволяет узнать размер памяти, необходимой для хранения адреса. Если же аргументом sizeof является ссылка, мы получим размер связанного с ней объекта.

Гарантируется, что в любой реализации С++ размер типа char равен 1.

// char_size == 1

size_t char_size = sizeof(char);

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

// правильно: константное выражение

int array[ sizeof(some_type_T)];

 






Не нашли, что искали? Воспользуйтесь поиском:

vikidalka.ru - 2015-2024 год. Все права принадлежат их авторам! Нарушение авторских прав | Нарушение персональных данных