2010-06-24 31 views
-1
class A { 
public: 
    A() { } 
    ~A() { cout << "A Destructor \n" ; } 
}; 

class B :public A{ 
    public: 
    B() { } 
    virtual ~B() { cout << "B Destructor \n" ; } 
}; 

class C : public B { 
    public: 
    C() { } 
    ~C() { cout << "C Destructor \n"; } 
}; 

int main() 
{ 

    A *pointA = new A; 
    A *pointB = new B; 
    A *pointC = new C; 

    delete pointA; 
    delete pointB; 
    delete pointC; 
} 
+4

这是功课吗? – Patrick 2010-06-24 10:36:44

+0

必须与帕特里克一致,闻起来像功课。 – Puppy 2010-06-24 10:45:35

+0

这不是作业。我试图理解,为什么会抛出未定义的行为? – user373215 2010-06-24 10:49:10

回答

10

它会在第二次(和第三次)删除时调用未定义的行为,因为A的析构函数不是虚拟的。

§5.3.5/ 3:

如果静态类型的操作数是从它的动态类型不同,则 静态类型应为基类操作数的动态型的和静态型应有一个虚拟析构函数或行为未定义。


如果你犯了一个虚拟的析构函数,你得到良好定义的行为,并动态类型的析构函数被调用。 (以及每个那些反过来的调用基析构函数)。您的输出将是:

析构函数
乙析
析构函数
Ç析
乙析
析构函数


什么是值得的,当你接近一个可编译的片段时,你应该离开t他包括。此外,只需使用struct而不是class来简化public的内容,并省略空的构造函数。

+0

非常感谢Gman。 – user373215 2010-06-24 12:15:23

0

正如GMan指出的,试图在基指针上调用delete操作符需要虚拟析构函数来让编译器能够正确销毁子类对象。很多人把这个过分简化为一条规则,比如“如果一个类有虚函数,它需要一个虚拟析构函数。”情况并非一定如此;即使没有虚函数的基类仍然需要虚析构函数,如果你想允许客户端通过基指针来删除类。如果你不这样做,析构函数应该受到保护,而不是公开的。

有一本很好的书,详细描述了这一点,更多的称为Herb Sutter的C++编码标准。我推荐它作为C++冒险的起点。 :-)