Преобразование dynamic_cast
Безопасно преобразует указатели и ссылки на классы вверх, вниз и вбок по иерархии наследования.
Содержание |
[править] Синаксис
)
}}
dynamic_cast< целевой-тип >( выражение )
|
|||||||||
целевой-тип | — | указатель на полный тип класса, ссылка на полный тип класса или указатель на (необязательно cv-квалифицированный) void |
выражение | — | lvalue (до C++11)glvalue (начиная с C++11) полного типа класса, если целевой-тип является ссылкой, prvalue указатель на полный тип класса, если целевой-тип это указатель. |
Если приведение успешно, dynamic_cast возвращает значение типа целевой-тип. Если приведение не удаётся, а целевой-тип является типом указателя, возвращается нулевой указатель этого типа. Если приведение не удаётся, а целевой-тип является ссылочным типом, генерируется исключение, соответствующее обработчику типа std::bad_cast.
[править] Объяснение
Для удобства описания "выражение или результат являются ссылкой на T
" означает, что "это glvalue типа T
", которое следует за соглашением decltype
.
С помощью dynamic_cast, можно выполнять только следующие преобразования, за исключением случаев, когда такие преобразования отбрасывают константность или волатильность.
Base
, а тип выражения является указателем или ссылкой на Derived
, где Base
это уникальный доступный базовый класс для Derived
, результатом является указатель или ссылка на подобъект класса Base
в объекте Derived
, указанный или идентифицированный выражением. (Примечание: неявное преобразование и static_cast также могут выполнять это преобразование.)Base
, а целевой-тип является указателем или ссылкой на тип Derived
выполняется проверка во время выполнения:Derived
, и если только один объект типа Derived
является производным от объекта, указанного/идентифицированного выражением, тогда результат приведения указывает/ссылается на этот объект Derived
. (Это известно как "приведение низ".)Derived
, результат приведение указывает/ссылается на этот Derived
(Это известно как "приведение в бок".)Подобно другим выражениям приведения, результат будет следующим:
|
(до C++11) |
|
(начиная с C++11) |
[править] Примечание
- Приведение вниз также можно выполнить с помощью static_cast, что позволяет избежать затрат на проверку во время выполнения, но безопасно только в том случае, если программа может гарантировать (с помощью как��й-либо другой логики), что объект, на который указывает выражение, определённо является
Derived
.
- Некоторые формы dynamic_cast полагаются на идентификацию типа во время выполнения (RTTI), то есть информацию о каждом полиморфном классе в скомпилированной программе. Компиляторы обычно имеют возможность отключить включение этой информации.
[править] Ключевые слова
[править] Пример
#include <iostream> struct V { virtual void f() {} // должен быть полиморфным, чтобы использовать проверку // dynamic_cast во время выполнения }; struct A : virtual V {}; struct B : virtual V { B(V* v, A* a) { // приведения во время создания (смотрите вызов в конструкторе D ниже) dynamic_cast<B*>(v); // чётко определено: v типа V*, V базовый для B, результатом // будет B* dynamic_cast<B*>(a); // неопределенное поведение: a имеет тип A*, A не является // базовым для B } }; struct D : A, B { D() : B(static_cast<A*>(this), this) {} }; struct Base { virtual ~Base() {} }; struct Derived: Base { virtual void name() {} }; int main() { D d; // самый производный объект A& a = d; // приведение вверх, dynamic_cast можно использовать, но это необязательно [[maybe_unused]] D& new_d = dynamic_cast<D&>(a); // приведение вниз [[maybe_unused]] B& new_b = dynamic_cast<B&>(a); // приведение в бок Base* b1 = new Base; if (Derived* d = dynamic_cast<Derived*>(b1); d != nullptr) { std::cout << "приведение вниз из b1 в d успешно\n"; d->name(); // безопасный вызов } Base* b2 = new Derived; if (Derived* d = dynamic_cast<Derived*>(b2); d != nullptr) { std::cout << "приведение вниз из b2 в d успешно\n"; d->name(); // безопасный вызов } delete b1; delete b2; }
Вывод:
приведение вниз из b2 в d успешно
[править] Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
Номер | Применён | Поведение в стандарте | Корректное поведение |
---|---|---|---|
CWG 1269 | C++11 | проверка времени выполнения не выполнялась для xvalue выражений , если целевой-тип являлся ссылочным типом rvalue |
выполняется |