Поделиться через


Приведение

В C++, если класс является производным от базового класса, содержащего одну или несколько виртуальных функций, можно использовать указатель на этот тип базового класса для вызова виртуальных функций в производном объекте класса. Класс, содержащий виртуальные функции, иногда называется "полиморфным".

Схема иерархии классов, где C является производным от B, который является производным от A.
Иерархия классов

Объект типа C можно визуализировать следующим образом:

Схема класса C с подобъектами B и A.
Класс C с вложенными объектами B и A

При наличии экземпляра класса Cесть B подобъект и A подобъект. Экземпляр C, содержащий подчиненные объекты A и B, является "полным объектом".

Так как производный класс полностью содержит определения всех базовых классов, производных от которых он является производным, он безопасно приведения указателя на любой из его базовых классов (также называемый переадресацией). Если указатель на базовый класс, он может быть безопасным для приведения указателя к экземпляру производного класса (также называемого даунт-рассылкой).

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

Для преобразования неполиморфных типов можно использовать оператор static_cast (в этом разделе объясняется различие между статическими и динамическими преобразованиями приведения, а также при необходимости их использования).

В следующем примере показано использование dynamic_cast и static_cast:

#include <iostream>

class Base {
public:
    virtual void print() { std::cout << "Base\n"; }
};

class Derived1 : public Base {
public:
    void print() override { std::cout << "Derived1\n"; }
};

class Derived2 : public Base {
public:
    void print() override { std::cout << "Derived2\n"; }
};

class MostDerived : public Derived1, public Derived2 {
public:
    void print() override { std::cout << "MostDerived\n"; }
};

int main() {
    MostDerived md;
    Base* b1 = static_cast<Derived1*>(&md); // Upcast to Derived1 is safe
    Base* b2 = static_cast<Derived2*>(&md); // Upcast to Derived2 is safe

    // Downcast to MostDerived is ambiguous and unsafe
    // MostDerived* md1 = static_cast<MostDerived*>(b1); // This won't compile
    // MostDerived* md2 = static_cast<MostDerived*>(b2); // This won't compile

    // Correct way to downcast in this situation
    MostDerived* md1 = dynamic_cast<MostDerived*>(b1); // This is safe
    MostDerived* md2 = dynamic_cast<MostDerived*>(b2); // This is safe

    md1->print(); // Prints "MostDerived"
    md2->print(); // Prints "MostDerived"

    return 0;
}

В этом разделе описываются следующие темы:

См. также

Выражения