返回信息流为什么基类的析构函数不为虚的话,基类指针指向子类对象,删除对象时,派生类的析构函数就不会被调用
谢谢各位
这是一条镜像帖。来源:北邮人论坛 / cpp / #74811同步于 2013/10/26
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
请教:关于基类的虚析构函数
Mulany
2013/10/26镜像同步10 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
本就不应该调用啊。
把析构函数看成普通成员函数,只不过删除指针对象时会自动通过指针来调用类的析构函数。通过指针调用非虚成员函数,当然不会根据你指向的对象来判断决定要调用谁了,而是会直接根据指针的类型直接调用相应函数。
为什么析构函数为虚函数,就即会调用子类的析构函数,又会调用基类的析构函数呢?不太明白原理
【 在 hdj 的大作中提到: 】
: 应该是用派生类对象初始化了基类对象的指针时会出现这种情况,造成内存泄露。如果是派生类对象初始化派生类对象的指针,会隐式生成析构函数,释放派生类的成员。
为什么析构函数为虚函数,就即会调用子类的析构函数,又会调用基类的析构函数呢?这才是我真正想问的,没表达清楚嘿嘿
【 在 sigmund 的大作中提到: 】
: 本就不应该调用啊。
: 把析构函数看成普通成员函数,只不过删除指针对象时会自动通过指针来调用类的析构函数。通过指针调用非虚成员函数,当然不会根据你指向的对象来判断决定要调用谁了,而是会直接根据指针的类型直接调用相应函数。
编译器会为每个有虚函数的类(不是类实例)维护一个虚函数表vftable,这些类的每个实例都含有一个vfptr,指向各自类的虚函数表,在虚函数表中,派生类的override函数会替换基类的对应函数,运行时,根据函数调用者的指针或者引用类型(基类还是派生类)来确定调用那个函数,就是运行时多态了。
推荐http://blog.csdn.net/haoel/article/details/1948051/,该作者是陈皓,coolshell.cn 的创建者。之前将其和 muduo 的作者陈硕弄混了。不好意思,两个牛人名字像,长得也像。去知乎看看陈硕的头像就知道了。
如果基类析构函数不是虚函数,Base *d = new Derived(); 这样定义的d在析构的时候只会调用Base自己的析构函数,delete d; 运行的时候,Derived自己的数据成员不会被销毁,造成内存泄漏。
如果基类析构函数是虚函数,上面例子中d对象由于多态会执行Derived定义的析构函数,完全销毁Derived实例的数据成员,至于之后还调用了Base的析构函数,是由于编译器对派生类析构函数做了处理,使其执行后仍需调用其基类析构函数。
更详细的解释在c++ primer作者的另一本深入理解c++对象模型里面。
讲的很详细,正是我不懂的地方。非常感谢
【 在 rollse 的大作中提到: 】
: 编译器会为每个有虚函数的类(不是类实例)维护一个虚函数表vftable,这些类的每个实例都含有一个vfptr,指向各自类的虚函数表,在虚函数表中,派生类的override函数会替换基类的对应函数,运行时,根据函数调用者的指针或者引用类型(基类还是派生类)来确定调用那个函数,就是运行时多态了。
: 推荐http://blog.csdn.net/haoel/article/details/1948051/,该作者是muduo的作者,c++ primer评注版的作者,文章很详细。
: 如果基类析构函数不是虚函数,Base *d = new Derived(); 这样定义的d在析构的时候只会调用Base自己的析构函数,delete d; 运行的时候,Derived自己的数据成员不会被销毁,造成内存泄漏。
: ...................
可是为啥在派生类中不用重写基类的虚析构函数呢
比如说下面的代码:
class A{
public:
virtual ~A(){ cout << "A::destructor" << endl;}
};
class B : public A{
public:
~B(){ cout << "B::destructor" << endl;}
};
B类并没有重写~A()函数,但是A* p = new B();delete p;会先调用~B(),然后调用~A(),如果按照虚函数的语义,delete p时,编译器不应该去找B类中是否重写了~A()函数么。那在处理虚析构函数时,岂不是与普通虚函数不一致?
【 在 rollse 的大作中提到: 】
: 编译器会为每个有虚函数的类(不是类实例)维护一个虚函数表vftable,这些类的每个实例都含有一个vfptr,指向各自类的虚函数表,在虚函数表中,派生类的override函数会替换基类的对应函数,运行时,根据函数调用者的指针或者引用类型(基类还是派生类)来确定调用那个函数,就是运行时多态了。
: 推荐http://blog.csdn.net/haoel/article/details/1948051/,该作者是muduo的作者,c++ primer评注版的作者,文章很详细。
: 如果基类析构函数不是虚函数,Base *d = new Derived(); 这样定义的d在析构的时候只会调用Base自己的析构函数,delete d; 运行的时候,Derived自己的数据成员不会被销毁,造成内存泄漏。
: ...................