Хотя существует несколько способов использования размещающего оператора 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(), вызов деструктора освобождает заданный объект, но не освобождает область, в которой располагается этот объект. При желании эту область можно использовать многократно.

Вызов деструктора удаляет объект, но не освобождает память.

<p>19.2. Идентификация типов времени выполнения</p>

Идентификацию типов времени выполнения (run-time type identification RTTI) обеспечивают два оператора.

• Оператор typeid, возвращающий фактический тип заданного выражения.

• Оператор dynamic_cast, безопасно преобразующий указатель или ссылку на базовый тип в указатель или ссылку на производный.

Будучи примененными к указателям или ссылкам на тип с виртуальными функциями, эти операторы используют динамический тип (см. раздел 15.2.3) объекта, с которым связан указатель или ссылка.

Эти операторы полезны в случае, когда в производном классе имеется функция, которую необходимо выполнить через указатель или ссылку на объект базового класса, и эту функцию невозможно сделать виртуальной. Обычно по возможности лучше использовать виртуальные функции. Когда применяется виртуальная функция, компилятор автоматически выбирает правильную функцию согласно динамическому типу объекта.

Но определить виртуальную функцию не всегда возможно. В таком случае может пригодиться один из операторов RTTI. С другой стороны, эти операторы более склонны к ошибкам, чем виртуальные функции-члены: разработчик должен знать, к какому типу следует привести объект, и обеспечить проверку успешности приведения.

Динамическое приведение следует использовать осторожно. При каждой возможности желательно создавать и использовать виртуальные функции, а не прибегать к непосредственному управлению типами.

<p>19.2.1. Оператор <code>dynamic_cast</code></p>

Оператор 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(bp)) {

 // использование объекта Derived, на который указывает dp

} else { // bp указывает на объект Base

 // использование объекта Base, на который указывает dp

}

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

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