请讲一讲基类指针指向派生类对象后指针释放过程?

hthuguangming 2002-10-28 12:28:25
class A
{
public
virtual ~A(){cout<<"x";}//这里一定要声明为虚函数为什么?
};

class B:public A
{
public
~B(){count<<"y";}
}
void main()
{
A*p=new B;
delete p;
}
如果类A的析构函数不声明为虚函数就会发生内存泄漏,我向高手请,教请详细说一下:

它是怎么在内存中存放的?

它是怎么去找到类B的析构函数?

它为什么要去调B的析构函数?

不是虚函数时为什么不去调用?
...全文
476 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
JoshuaLi 2002-12-24
  • 打赏
  • 举报
回复
A *p = new B; 指向派生类型的基类指针,delete p 时会调用确切类型的析构(如能够晚绑定,析构为virtual。否则按字面类型绑定)。对象的生死:基对象构造->派生对象构造...派生对象析构->基对象析构,哈哈
ITMSC 2002-12-24
  • 打赏
  • 举报
回复
你可以参考一些有关“虚函数表”的文章。
JoshuaLi 2002-12-24
  • 打赏
  • 举报
回复
up
magicblue 2002-11-19
  • 打赏
  • 举报
回复
your reading book is <inside c++ object model>?
i think you have to improve yourself rather than reading this book
at this time.for example,as if you don't understand the effect of
virtual function.
why become ~A() to virtual? because you let a pointer of A to a
object of B,then you write this "delete p;"(note p type is A),this
action will correctlly call B's destructor rather A's.how to call
or find ~A() or ~B() is compiler business,not yours.

and you painful misunderstanding i want to claim is that you have
not the conscious about OO.derived class destructor call based
class is natual.because derived class is a part of or IS-A based
class.the process of destruction is destruct the derived class
object own part,follow that,destruct the based class object part.
hthuguangming 2002-11-19
  • 打赏
  • 举报
回复

to cutcutcutcut:
好了,现在destructor在VTBL里了,可以通过VPTR执行B的destructor了。
执行完B的destructor后,系统立即知道p指向是个B,B有SUPERCLASS,编译时刻
就知道了,按照规则在执行A的destructor。

按照规则?
我不明白在哪里有这样的规则:调了子类的析构函数后一定去调用基类的析构函数

子类的析构函就不是这样写的
~B(){....;~A();}
Vicart 2002-11-14
  • 打赏
  • 举报
回复
--------------------
A*p=new B;
delete p;
--------------------

delete p时,编译器只是根据指针p的类型调用其析构函数,然后调用其父类的析构函数。

这里指针p的类型为A,所以delete p执行A的析构函数,但这里p指向的内存包含了B追加分配的空间,所以仅执行A的析构函数会造成内存泄漏。因此,delete p时必须执行B的析构函数。通过父类型调用子类的函数当然通过虚机制了。

因此,A的析构函数必须虚化,这样delete p时,编译器不是直接生成调用A的析构函数的调用指令,而是通过虚函数表计算出析构函数的入口地址,然后跳转到该地址处执行。而虚函数表的内容是创建实际对象时初始化的,因此虚函数表中的析构函数表项是指向B的析构函数的入口的。所以delete p调用了B的析构函数。
mybilly2016 2002-11-14
  • 打赏
  • 举报
回复
]]>
cutcutcutcut 2002-11-11
  • 打赏
  • 举报
回复
说二句哦,不对多指教:
首先把destructor当做一个normal method来看,为何destructor要为virtual:
因为如果不是virtual,destructor就不能放进 VTBL,
"如果不能放进VTBL",
你delete p,不管p是一个A还是一个B,那肯定是调用的A的destructor。
因为编译器,只知道p是个A的TYPE!!
好了,现在destructor在VTBL里了,可以通过VPTR执行B的destructor了。
执行完B的destructor后,系统立即知道p指向是个B,B有SUPERCLASS,编译时刻
就知道了,按照规则在执行A的destructor。
其实在这儿根本没有必要写个destructor,因为你没有需要清理的东西。让编译器
自己去用最好的方式去做就行了。
啥时需要呢,你的A真正需要去显式去做一个清理时,例如在A中有个datamember
需要释放内存等等。
不过我的习惯在作为一个interface的class仅仅只声明method而不声明datamember.为何,这样好处很多。。。哈哈,
好久没上来了,扯远了,这个问题以后谈
fuchong 2002-11-05
  • 打赏
  • 举报
回复
其实这就是是个机制的问题!在设计语言是就有这个规律!如果要很深的了解这个问题。那么你就要很深的功底
nk_rainfall 2002-11-03
  • 打赏
  • 举报
回复
其实你关键要明白一个问题:编译时决定和运行时决定的区别。
不为虚函数的函数,直接按你编译时的类型来决定调用哪个函数。
为虚函数的函数,在运行是动态识别类型并依据虚函数表来调用相应类型的函数。
freewing 2002-11-03
  • 打赏
  • 举报
回复
你要明白这个问题,强烈建议《Thinking in C++》
Louis819 2002-11-03
  • 打赏
  • 举报
回复
唉!楼主还是没有理解虚函数的功能和作用。子类的析构函数是对基类析构函数的重载,虚析构函数和一般析构函数是一样的。
Flamesong 2002-11-01
  • 打赏
  • 举报
回复
强烈建议你看<<深度探索C++对象模型>>。
Last_Dodo 2002-10-30
  • 打赏
  • 举报
回复
准确些说“从调用的起点开始依继承次序调用所有的析构函数”应该改为“从调用的起点开始依继承次序调用所有的父类析构函数”
Last_Dodo 2002-10-30
  • 打赏
  • 举报
回复
虚函数是通过一张存有函数入口地址的表来实现的。比如:
A是基类,B是派生类。
A *ap = new B();
在构造B时编译器会将B的虚函数的入口地址放入那张表中。当你通过ap来调用虚函数时,编译器会产生适当的代码从那张表中取得函数的入口地址。由于里面放的是B的虚函数入口地址所以调用的是B类的函数。如果你把它改成ap = new A(),那么ap里的那张表装的是A的虚函数入口地址,所以通过ap将调用A的虚函数。在C++中如果函数(构造函数除外)在基类被申明为虚则在所有派生类中都是虚函数(不管你是否用来virtual这个关键字)。这就是为什么如果A类的析构函数是虚的时候,调用的是B的析构函数。另外,析构函数的调用和一般的函数调用有一个重要差别,就是从调用的起点开始依继承次序调用所有的析构函数。

如果函数不是虚函数,编译器只是简单的按类来找到被调用的函数入口来调用该函数。所以如果A的析构函数不是虚的话,它只调用A的析构函数而不会调用B的析构函数。

希望有所帮助并不嫌罗嗦。
muche 2002-10-30
  • 打赏
  • 举报
回复
up
liu_feng_fly 2002-10-29
  • 打赏
  • 举报
回复
动态绑定到应该调用的函数上,这正是虚函数的特点。关于这一点,可以看看c++书籍上关于vptr和vtable的讲解。
hthuguangming 2002-10-29
  • 打赏
  • 举报
回复
to jiaclssmate:
因为你实际上是构造了一个派生类的对象,用基类的指针指向这个对象,而实际上基类并不存在,所以调用派生类的构造函数。

我问当你调用子类构造函数时派生类对象不构造吗?我认为
A *p=new B这句话构造了两个无名对象一个是子类对象一个是基类对象。

如果不把析构函数声明为虚函数,基类的指针就会调用基类的析构函数,而基类实际并不存在,所以会出问题。
我认为它不会出错只是内存内存泄漏罢了。


hthuguangming 2002-10-29
  • 打赏
  • 举报
回复
我如果这样声明
void main()
to jiaclassmate:
void main()
{
B xy;
//基类析构函数不声明为虚函数当xy析构(基类析构函数不声明为虚函数)时它会自动调用基类的析构函数,
而 A *P= new B;这句话也是构造基类对象后再构造子类对象,为什么基类析构函数
不声明为虚函数当delete P时,只调用基类的析构函数呢?两者我认为没有什么区别
只不过一个是自动归还一个是手动归还内存.请高手特别高手中的高手earthharp指教.
}
jiaclassmate 2002-10-29
  • 打赏
  • 举报
回复
子类的构造函数当然要调用基类的构造函数。在析构时如果只调用基类的析构函数那子类的成员该如何处理呢?
关于A *p = new B其实只有一个子类对象,其中有一块内存是基类的。
加载更多回复(8)

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧