Хотя существует несколько способов использования размещающего оператора new
, он похож на функцию-член construct()
класса allocator
, но с одним важным отличием. Передаваемый функции construct()
указатель должен указывать на область, зарезервированную тем же объектом класса allocator
. Указатель, передаваемый размещающему оператору new
, не обязан указывать на область памяти, зарезервированной функцией operator new()
. Как будет продемонстрировано в разделе 19.6, переданный выражению размещающего оператора new
указатель даже не обязан указывать на динамическую память.
Подобно тому, как размещающий оператор new
является низкоуровневой альтернативой функции-члену allocate()
класса allocator
, явный вызов деструктора аналогичен вызову функции destroy()
.
Вызов деструктора происходит таким же образом, как и любой другой функции-члена объекта: через указатель или ссылку на объект:
string *sp = new string("a value"); //
//
sp->~string();
Здесь деструктор вызывается непосредственно. Для получения объекта, на который указывает указатель sp
, используется оператор стрелки. Затем происходит вызов деструктора, имя которого совпадает с именем типа, но с предваряющим знаком тильды (~
).
Подобно вызову функции destroy()
, вызов деструктора освобождает заданный объект, но не освобождает область, в которой располагается этот объект. При желании эту область можно использовать многократно.
19.2. Идентификация типов времени выполнения
• Оператор typeid
, возвращающий фактический тип заданного выражения.
• Оператор dynamic_cast
, безопасно преобразующий указатель или ссылку на базовый тип в указатель или ссылку на производный.
Будучи примененными к указателям или ссылкам на тип с виртуальными функциями, эти операторы используют динамический тип (см. раздел 15.2.3) объекта, с которым связан указатель или ссылка.
Эти операторы полезны в случае, когда в производном классе имеется функция, которую необходимо выполнить через указатель или ссылку на объект базового класса, и эту функцию невозможно сделать виртуальной. Обычно по возможности лучше использовать виртуальные функции. Когда применяется виртуальная функция, компилятор автоматически выбирает правильную функцию согласно динамическому типу объекта.
Но определить виртуальную функцию не всегда возможно. В таком случае может пригодиться один из операторов RTTI. С другой стороны, эти операторы более склонны к ошибкам, чем виртуальные функции-члены: разработчик должен
19.2.1. Оператор dynamic_cast
Оператор dynamic_cast
имеет следующую форму:
dynamic_cast<
dynamic_cast<
dynamic_cast<
где
должен быть типом класса, у которого (обычно) есть виртуальные функции. В первом случае е
— допустимый указатель (см. раздел 2.3.2); во втором — l-значение, а в третьем — не должен быть l-значением.
Во всех случаях тип указателя е
должен быть либо типом класса, открыто унаследованным от
назначения, либо открытым базовым классом
назначения, либо самим
назначения. Если указатель е
будет одним из этих типов, то приведение окажется успешным. В противном случае приведение закончится ошибкой. При неудаче приведения к типу указателя оператор dynamic_cast
возвращает 0. При неудаче приведения к типу ссылки он передает исключение типа bad_cast
.
dynamic_cast
для типа указателяДля примера рассмотрим класс Base
, обладающий по крайней мере одной виртуальной функцией-членом, и класс Derived
, открыто унаследованный от класса Base
. Если имеется указатель bp
на класс Base
, то во время выполнения можно привести его к указателю на тип Derived
следующим образом:
if (Derived *dp = dynamic_cast
//
} else { //
//
}