Downcast Base класса на несколько "поколений" вперёд

Имеется класс A, от него наследуется класс B, от которого наследуется класс C. Как произвести приведение типов из A в C?

Код, с которым провожу эксперименты:

#include <iostream>
#include <string>
#include <memory>
using namespace std;

class A
{
public:
    string str;
    A(string _str)
    {
        str = _str;
    }
    virtual ~A(){}
};

class B : public A
{
public:
    virtual string unpack(string t) = 0;
    virtual ~B(){}
};

class BA : public B
{
public:
    string unpack(string t) override
    {
        string temp = "a";
        return temp + str + t;
    }
    virtual ~BA(){}
};

class BB : public B
{
public:
    string unpack(string t) override
    {
        string temp = "a";
        return temp + str + t;
    }
    virtual ~BB(){}
};

template <typename TypeC>
TypeC *convert(A *_msg)
{
    auto msg = dynamic_cast<TypeC*>(_msg);
    return msg;
}

int main()
{
    A* a = new A("TEST_A");
    auto ba = convert<BA>(a);
    cout << ba->unpack("TEST_BA") << endl;
    return 0;
}

Ответы (1 шт):

Автор решения: Harry

Конечно же, вы не можете привести реальный объект A к типу AB!

А вот AB через указатель на A - можете.

Только надо дописать конструкторы...

class A
{
public:
    string str;
    A(string _str)
    {
        str = _str;
    }
    virtual ~A(){}
};

class B : public A
{
public:
    B(string _str):A(_str){}
    virtual string unpack(string t) = 0;
    virtual ~B(){}
};

class BA : public B
{
public:
    BA(string _str):B(_str){}
    string unpack(string t) override
    {
        string temp = "a";
        return temp + str + t;
    }
    virtual ~BA(){}
};

class BB : public B
{
public:
    string unpack(string t) override
    {
        string temp = "a";
        return temp + str + t;
    }
    virtual ~BB(){}
};

template <typename TypeC>
TypeC *convert(A *_msg)
{
    auto msg = dynamic_cast<TypeC*>(_msg);
    return msg;
}

int main()
{
    A* a = new BA("TEST_A");
    auto ba = convert<BA>(a);
    cout << ba->unpack("TEST_BA") << endl;
    return 0;
}

Вот оно, главное -

    A* a = new BA("TEST_A");

Т.е. указатель на A указывает на самом деле на объект BA - и вот такой указатель вы можете привести к указателю на BA.

А вот если вы создали объект A - то как вы себе представляете приведение его к наследнику? У него же просто нет нужной функции unpack...

Чтобы убедиться - вам надо было в своем коде проверить результат преобразования:

A* a = new A("TEST_A");
auto ba = convert<BA>(a);

cout << ba << endl;

И вы бы увидели, что преобразование не выполнено: ba == nullptr...

→ Ссылка