Dynamic_cast с неоднозначным целевым классом

Я как раз читал новую книгу Страуструпа. В главе 22.2.2 он обсуждает проблему dynamic_cast.

Код, который я написал, чтобы проверить это сам, выглядит следующим образом:

class Storable  
{
public:
    int i;
    virtual void r() {};
    Storable()  
    {
        i = 1;
    };
};

class Component:public virtual Storable
{
public:
    Component()  
    {
        i = 1;
    };
};

class Receiver:public Component
{
public:
    Receiver()  
    {
        i = 2;
    };
};

class Transmitter:public Component
{
public:
    Transmitter()  
    {
        i = 3;
    };
};

class Radio:public Transmitter
{
public:
    Radio()  
    {
        i = 4;
    };
};


int _tmain(int argc, _TCHAR* argv[])
{
    Radio *r = new Radio();
    Storable *s1 = dynamic_cast<Storable*>(r);

    Component *c = dynamic_cast<Component*>(s1);  // this should be 0 but it is not!

    return 0;
}

Строструп объясняет, что c должен быть nullptr, поскольку невозможно узнать, о какой версии Storable идет речь. Тем не менее, я получаю это как действительный указатель.

Я предполагаю, что Страуструп, вероятно, прав в этом, но я не вижу, что тонко я упустил, может ли кто-нибудь еще это заметить?


person Stefan    schedule 30.09.2013    source источник
comment
class Component:public virtual Storage — попробуйте удалить ключевое слово virtual здесь и посмотрите, что произойдет ( en.wikipedia.org/wiki /Virtual_inheritance ).   -  person Mateusz Kołodziejski    schedule 30.09.2013
comment
@MateuszKołodziejski По-прежнему ничего - пример OP представляет собой чисто линейную иерархию с одним наследованием.   -  person Angew is no longer proud of SO    schedule 30.09.2013
comment
@Mateusz, он отлично работает и без этого, так как для каждого компонента есть отдельное хранилище. Предполагается, что проблема заключается в том, что для обоих компонентов существует общее хранилище, а dynamic_cast не знает, какое из них использовать, и возвращает nulptr.   -  person Stefan    schedule 30.09.2013
comment
@Angew без каких-либо виртуальных методов это не был бы тип полиморфного класса, и поэтому динамическое приведение не могло бы быть приведено вниз   -  person msam    schedule 30.09.2013
comment
@msam Я имел в виду виртуальное наследование, а не виртуальную функцию-член.   -  person Angew is no longer proud of SO    schedule 30.09.2013
comment
@Stefan Ах, да, действительно - здесь вы не делаете множественного наследования. Тогда не беспокойся.   -  person Mateusz Kołodziejski    schedule 30.09.2013
comment
@MateuszKołodziejski, не беспокойтесь, спасибо за попытку помочь!   -  person Stefan    schedule 30.09.2013
comment
Вы имели в виду, что радио должно происходить как от передатчика, так и от приемника?   -  person Sean    schedule 30.09.2013
comment
@ Шон, да - взгляните ниже на ответ Ангью на вопрос о том, как мне легче всего поставить себя в неловкое положение на форуме.   -  person Stefan    schedule 30.09.2013


Ответы (1)


Я не вижу здесь двусмысленности. Вы правильно расшифровали пример? Цитирование С++ 11, [expr.dynamic.cast]§8 (с использованием dynamic_cast<C*>(v)):

... если v указывает (ссылается) на общедоступный подобъект базового класса самого производного объекта, а тип самого производного объекта имеет базовый класс типа C, который является однозначным, и public, то результат указывает (ссылается) к подобъекту C самого производного объекта.

Ваш v равен s1, который указывает на подобъект Storable наиболее производного объекта типа Radio. В Radio есть только один подобъект базового класса типа Component, и он является общедоступным, поэтому динамическое приведение должно пройти успешно, как это и происходит.

Было бы двусмысленно, если бы Radio также производилось от Receiver; может вы это пропустили?

person Angew is no longer proud of SO    schedule 30.09.2013