`dynamic_cast` от базового до производного - PullRequest
10 голосов
/ 02 апреля 2012

Да, я знаю, что downcast с использованием dynamic_cast не может скомпилироваться, если Base не полиморфен, но моя проблема не в этом.

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

class Derived: public Base {
    public:
        void foo()
        {
            cout << "foo\n";
        }
};

int main()
{
    Base *pb;
    Derived *pd;

    pb = new Derived;  //Base* points to a Derived object
    pd = dynamic_cast<Derived*>(pb); 
    pd->foo();  //outputs foo

    pb = new Base;  //Base* points to a Base object
    pd = dynamic_cast<Derived*>(pb);  
    pd->foo();  //outputs foo, too. Why?
}

Я думал, когда pb = new Derived;, pb на самом деле указывает на то, что Derived объект лежит в куче. После pd = dynamic_cast<Derived*>(pb);, pd также указывает на этот Derived объект, поэтому pd->foo() должно быть в порядке.

Но когда pb = new Base;, на что pb указывает объект Base в куче, то после pd = dynamic_cast<Derived*>(pb); как может pd->foo() работать? dynamic_cast превратил Base объект в куче в Derived объект?

Ответы [ 4 ]

17 голосов
/ 02 апреля 2012

В C ++ каждый экземпляр класса имеет свою собственную версию типов данных, но все классы совместно используют одну и ту же функцию в памяти (кроме встроенных функций).В вашем случае, когда вы говорите что-то вроде:

pd->foo();

Вы, по сути, вызываете Derived::foo, которая является функцией в памяти, и компилятор знает, где она находится.Дело в том, что он вообще не зависит от pd.Однако, если у вас было что-то вроде этого:

class Derived : public Base {
    private:
        int a;

    public:
        Derived() { a = 100; }

        void foo() {
            std::cout<<a<<std::endl;
        }
 };

Тогда pd->foo() вызовет ошибку сегментации.Здесь ваше динамическое приведение не выполнено, и когда вызывается Derived::foo, ему передается 0 как объект this.В предыдущем случае все было в порядке, поскольку объект this никогда не использовался.Однако во втором случае он используется и, следовательно, вызывает ошибку сегментации.

7 голосов
/ 02 апреля 2012

В вашем foo у вас нет доступа к this, который в этом случае должен быть NULL. Это то, что dynamic_cast возвращается, когда невозможно выполнить приведение.

По сути, вы находитесь в области "неопределенного поведения".

6 голосов
/ 02 апреля 2012

Вы столкнулись с неопределенным поведением.Вы должны проверить тип возвращаемого значения dynamic_cast.

pd = dynamic_cast<Derived*>(pb);  

. Это возвращает ноль, и вы вызываете функцию по указателю NULL.Все может случиться.

1 голос
/ 02 апреля 2012

Пожалуйста, всегда предпочитайте проверять, успешен ли актерский состав, прежде чем пытаться его использовать.Я предполагаю, что это преимущество использования кастинга.Вы можете проверить, успешно ли это или нет.

pd = dynamic_cast<Derived*>(pb);  
if(pd!=NULL)
  pd->foo();

В случае неудачного приведения pd имеет значение NULL.Не используйте pd, если вы не уверены, что оно имеет значение.а затем только де ссылки на него

...