【C++】const参照とshared_ptrをダウンキャストする

const 参照と shared_ptr のダウンキャスト方法です。

先に方法を書いておきますが以下の通りです。

// const参照のダウンキャスト
auto&/*const Type&*/ sub = static_cast<const Type&>(obj);

// shared_ptrのダウンキャスト
std::shared_ptr<Type> sub = std::dynamic_pointer_cast<Type>(ptr);

説明

以下のように Base を継承した Derived クラス定義があったとします。

class Base
{
public:
    int a = 0;
    
    virtual ~Base() { }
};

class Derived : public Base
{
public:
    int b = 0;
};

const参照ダウンキャスト例

const 参照は以下の操作でダウンキャストできます。

// 例えばこんな感じの定義があったとして
class Sample
{
    Derived d;
public:

    const Base& GetObj() {
        return d;
    }
};

// 以下のような受け方をするとサブクラスにダウンキャストできる
Sample s;
auto& b0 = s.GetObj();
if (typeid(b0) == typeid(Derived))
{
    const Derived& d = static_cast<const Derived&>(b0);
    std::cout << d.a << ", " << d.b << std::endl;
}

ちなみに以下のようなコードを書くと(当たり前ですが)うまくいきません。

const Base& Bar()
{
    Derived d;
    d.a = 100;
    d.b = 200;
    return d; // 誰も保持しないconst参照返しはNG
}

// 上記のこーをを以下のように受ける

// ダウンキャスト不可
//  → スライス & コピーで消える
auto b1 = Bar();
if (typeid(b1) == typeid(Derived))
{
    const Derived& d = static_cast<const Derived&>(b1); // 絶対に入らない
    std::cout << d.a << ", " << d.b << std::endl;
}

// これを参照受けすると誰も保持しない参照でエラーになる
auto& b2 = Bar();
if (typeid(b2) == typeid(Derived)) // error: bad access
{
    const Derived& d = static_cast<const Derived&>(b2);
    std::cout << d.a << ", " << d.b << std::endl;
}

shared_ptrダウンキャスト例

以下のように shared_ptr を返すメソッドが多態性を持つ場合受け取ったときの判定方法とダウンキャスト方法は以下の通りです。

// 生成側
std::shared_ptr<Base> Foo()
{
    std::shared_ptr<Derived> d = std::make_shared<Derived>();
    d->a = 100;
    d->b = 200;
    return d;
}

// 利用側
auto sptr_base = Foo();
if (typeid(*sptr_base) == typeid(Derived))
{
    std::shared_ptr<Derived> sptr_b = std::dynamic_pointer_cast<Derived>(sptr_base);
    std::cout << sptr_b->a << ", " << sptr_b->b << std::endl;
}

以上