是的,我知道如果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
对象?
答案 0 :(得分:17)
在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
对象从未使用过。但是,在第二种情况下,它被使用,因此导致分段错误。
答案 1 :(得分:7)
在您的foo
中,您无法访问this
,在这种情况下应为NULL
。这就是dynamic_cast
在无法完成演员表时返回的内容。
基本上你在这里的“未定义行为”区域。
答案 2 :(得分:6)
您遇到了未定义的行为。您应该检查dynamic_cast
的返回类型。
pd = dynamic_cast<Derived*>(pb);
返回null,并在NULL
指针上调用函数。任何事情都可能发生。
答案 3 :(得分:1)
在尝试使用之前,请务必先检查演员表是否成功。我猜它是使用铸造的优势。你可以检查一下是否成功。
pd = dynamic_cast<Derived*>(pb);
if(pd!=NULL)
pd->foo();
如果转换失败pd
的值为NULL。除非您确定它具有值,否则请勿使用pd
。然后只引用它