`dynamic_cast` от Base to Derived
Да, я знаю, что 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
?
Ответы
Ответ 1
В С++ каждый экземпляр класса имеет свою собственную версию типов данных, но все классы используют одну и ту же функцию в памяти (кроме встроенных функций). В вашем случае, когда вы говорите что-то вроде:
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
никогда не использовался. Однако во втором случае он используется и, следовательно, вызывает ошибку сегментации.
Ответ 2
В вашем foo
вы не получаете доступ к this
, который в этом случае должен быть NULL
. Это то, что dynamic_cast
возвращает, когда выполнение не может быть выполнено.
В основном вы находитесь в области "undefined".
Ответ 3
Вы используете поведение undefined. Вы должны проверить тип возврата dynamic_cast
.
pd = dynamic_cast<Derived*>(pb);
Это возвращает null, и вы вызываете функцию на указателе NULL
. Все может случиться.
Ответ 4
Пожалуйста, всегда предпочитайте проверять, успешно ли выполняется бросок, прежде чем пытаться его использовать. Я предполагаю, что это преимущество использования кастинга. Вы можете проверить, успешно ли это или нет.
pd = dynamic_cast<Derived*>(pb);
if(pd!=NULL)
pd->foo();
Если сбой выполнения pd
имеет значение NULL. Не используйте pd
, если вы не уверены, что оно имеет значение. а затем только ссылку на него