C++ では、1 つ以上の仮想関数を含む基底クラスからクラスが派生している場合、その基底クラス型へのポインターを使用して、派生クラス オブジェクト内の仮想関数を呼び出せます。 仮想関数を含むクラスは、"ポリモーフィックなクラス" と呼ばれます。
クラスの階層構造
C
型のオブジェクトは、次のように視覚化できます。
サブオブジェクト B とサブオブジェクト A を持つクラス C
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;
}
このセクションは、次のトピックで構成されています。