文章目录中虚拟析构函数的父指针指向子对象||子指针指向父对象的总结:
析构函数
《Effective C++》
当派生类(derived class)对象由一个基类(base class)指针删除时,若基类有一个非虚函数(non-virtual)的析构函数时,其结果是未定义的——实际执行时通常发生的是对象的派生类部分没有被销毁例如:
# includeiostreamusingnamespacestd; class shape { public : shape (} { cout ' crat : shape ' endl; (} ~Shape ) ) { cout 'DEST: shape' endl; }; class player { public : player (} { cout ' crat : player ' endl; (} ~Player ) ) { cout 'DEST: player' endl; }; class ball { public : ball (} { cout ' crat : ball ' endl; (} ~Ball ) ) { cout 'DEST: ball' endl; }private: Shape shape_; (; class football : public ball { public : football () { cout 'CRAT: football' endl; (} ~Football () { cout 'DEST: football' endl; }private: Player players_; (; int main () { Ball *ball=new Football ); 删除球; 返回0; }上的示例程序的输出结果如下。
在crat : shape crat 3360 ball crat : player crat : football dest : ball dest : shape中,如果基类指针指向派生类对象,请将对象
为了避免上述问题,不是可以为每个类声明虚拟析构函数吗? 考虑以下示例:
class point { public : point (intx,int y ); ~Point (; private: int x_,y_; (; 上述Point类在32位计算机上占用的内存空间为8字节。 如果将Point类析构函数指定为虚函数,则Point类必须提供指向由函数指针组成的数组(vtbl,virtal table )的vptr (即,virtual table pointer )指针每个具有虚函数的类都有对应的vtbl。 当对象调用某个虚函数时,实际调用的函数取决于该对象的vptr所指向的vtbl。 因此,将所有类的析构函数徒劳地声明为虚函数也是错误的。
父类指针指向子类对象||子类指针指向父类对象没有调用派生类成员对象及派生类自身的析构函数,而只是调用了基类成员对象及基类的析构函数
1.当自己的类指针指向自己类的对象时,无论调用的是虚函数还是实函数,其调用的都是自己的:
2.当指向父类对象的父类指针被强制转换成子类指针时候,子类指针调用函数时,只有非重写函数是自己的,虚函数是父类的;
上面的三个词概括为一句话,如果父类的子类具有同名的非虚函数,则会调用转换后的指针类型函数
如果父类的子类具有同名的虚函数怎么办? 调用在指针转换前指向的对象类型函数。
如果基类指针指向派生类,则只能处理派生类从基类继承的数据。
指向派生类的指针比基类的内存空间长,访问时会引起内存溢出,因此不允许指向派生类的指针指向基类。
1 .每个析构函数(不加虚拟)只负责清除自己的成员。
2 .有基类指针,可能指确实是派生类成员的情况。 (这很正常)
在中,生成指向派生类成员的基类指针后,程序将变得不知道该怎么办。
因此,基类中的析构函数必须是虚拟析构函数,以确保正确执行析构函数。
基类指针可以指向派生类中的对象,该指针delete []p; 调用该指针指向的派生类的析构函数,派生类的析构函数自动调用基类的析构函数,从而完全释放整个派生类中的对象。 如果析构函数未声明为虚函数,则编译器在实现静态绑定并删除基类指针时只会调用基类的析构函数,而不会调用派生类的析构函数。 这导致派生类对象的析构函数不完整。 因此,有必要将析构函数声明为虚函数。
只有将类用作基类时,才能将析构函数写为虚函数。
3.当指向子类对象的子类指针被强制转换成父类指针的时候,也就是父类指针指向子类对象,此时,父类指针调用的虚函数都是子类的,而非虚函数都是自己的;
子类通常包含父类中没有的成员变量或方法函数。 子类始终包含父类的所有成员变量和方法函数。 因此,如果用父类指针指向子类,则没有问题。 因为父类中有,也在子类中,所以不会发生非法访问问题。
但是,如果用子类指针指向父类,则访问子类特定的方法函数和成员变量时会发生错误。 因为子类指针指向的父类创建的对象根本没有可访问的对象。 它们特定于子类,并且仅在子类中初始化对象时存在。
总结:具有多态性性质的基类必须声明虚拟析构函数。 另外,如果类包含其他虚拟函数,则必须具有虚拟析构函数。
如果类不是用作基类,或者不是为了具有多态性而设计的,则不应该声明虚拟析构函数。