基类虚析构函数分析

发布时间:2014-10-23 23:26:50
来源:分享查询网

多态是由虚函数表来实现,通过父类指针来实现动态绑定。子类重写父类的虚函数后,覆盖虚函数表中父类该虚函数在表中原来的位置,也许“覆盖”也就是由此得称。     那析构函数是否也如此呢?程序代码中经常可以见到将基类的析构函数写成虚函数,目的就是为了防止由以下这种情况造成的内存泄漏:        class A;       class B : public A{};       ......   B *b = new B();       A *p = (A*)b;       delete p;        此时系统仅调用了A的析构函数,并没有调用B的析构函数,为什么呢?指针p指向的是B的对象啊!     而且,为什么将A的析构函数写成虚函数,通过A类指针来delete就能调用析构B呢?难道又是动态绑定?可是,动态绑定的前提是两个函数要有一致的声明啊,这里就算是~A();是virtual的,那也不能说会动态绑定到~B();去啊,起码它们不是同名的。   打开VC调试后,在watch窗口查看后得知,指针p和b的值一样,可是把“+”展开后看到的却不一样,p展开后竟然没有看到B的成员变量,由此猜测:这样的话,那类B独有的函数也同样不能调用了(废话,谁这么用过)。那也就是说,通过指针p来delete,调用的当然也是A的析构函数了,难怪B的析构函数没被调用。   A析构写成虚函数后发现,B对象的虚函数表里(展开指针p的“+”后)就出现了B的析构函数相关信息,它覆盖了原来A的虚析构函数,也只能覆盖(怎么覆盖?这个......),否则通过基类指针不知要调用哪个函数(这么猜不知对不对)。然后根据析构的顺序,再调用A的析构函数。   还有一个问题,为什么指针b转化为A类指针后,类B独有的成员会不见呢,而且,虚函数表指针也是类B独有的,为什么它就还能留在那儿。这得从C++的对象内存模型说起brabra...,估计应该跟截断技术有关,从派生层次上看(通过基类派生类的构造顺序看),构造一个派生类对象时,先构造父类的成员变量,然后......而C++为类对象结构的头四个字节初始化为虚函数表指针(从单继承的角度),所以,截断的时候仍然保留了(呵呵,是这样吧)。

返回顶部
查看电脑版