VerySource

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
楼主: 心碎飞了

关于virtual的析构函数

[复制链接]

0

主题

3

帖子

3.00

积分

新手上路

Rank: 1

积分
3.00
发表于 2021-3-9 00:45:01 | 显示全部楼层

firegun 如果析构函数不用virtual,则
Base *p = new Derive();
delete p;
这里delete p删除的就是Derive类中的Base成份了,而对于Derive成员则无法删除,所以为了正确删除,则必须用virtual析构函数,具体请参考effective c++ 3td

//无三先生这段讲得很明白了。两个不是一个概念
回复

使用道具 举报

0

主题

2

帖子

2.00

积分

新手上路

Rank: 1

积分
2.00
发表于 2021-3-9 01:15:02 | 显示全部楼层
1>>>>我上面理解的对不对?
2>>>>为什么 若没有virtual,delete p;就少调用一个析构函数?
3>>>>为什么若有virtual,delete p;就调用两个析构函数?
==============
     一个派生类的析构函数最后是会自动调用基类的析构函数的.这就象派生类构造函数在一定条件下会自动调用基类的无参构造函数一样.
     如果一个基类析构函数置为virtual,那么派生类并不是说会继承基类的析构函数,而是会继承"虚"的机制,派生类析构也会置为virtual. 此时,当一个基类指针实际指向派生类,在delete的时候,发生的是动态绑定,正确调用到派生类的析构函数,但派生类的析构函数只会析构派生类新增加的部分,从基类继承的部分,要靠基类的析构函数来析构,而基类的析构函数是由派生类析构函数执行完毕时自动调用的.
      相反,如果基类析构函数不为虚,派生类析构函数也就不为虚.当一个基类指针实际指向派生类,在delete的时候,发生的是静态绑定,编译器根据指针的类型直接绑定到基类析构函数,自然派生类的析构函数就不会被调用.

    并不是所有用于继承的类的析构函数都要置为virtual,只有 有多态目的的基类的析构函数才置为virtual.
回复

使用道具 举报

0

主题

2

帖子

2.00

积分

新手上路

Rank: 1

积分
2.00
发表于 2021-3-9 02:15:01 | 显示全部楼层
当一个基类指针实际指向派生类
==>
当一个基类指针实际指向派生类的对象
回复

使用道具 举报

0

主题

2

帖子

3.00

积分

新手上路

Rank: 1

积分
3.00
发表于 2021-3-9 02:30:01 | 显示全部楼层
请楼主参考Effective C++,
看下面的情况:
base *b = new derive();
delete b;
这段代码应该是合法的,编译也能够得到通过,但是行为却不是我们所预期的,
我们期望delete删除derive对象占用的全部资源,但是,如果我们没有给~base()函数加
virtual的话delete的实际行为只是释放了对象的base部分,而对象的derive特有部分将
不被释放,成为资源泄露的隐患。
加上virtual就是提示delete调用derive版的析构函数。
回复

使用道具 举报

1

主题

13

帖子

5.00

积分

新手上路

Rank: 1

积分
5.00
 楼主| 发表于 2021-3-9 04:00:02 | 显示全部楼层
非常感谢大家!我从中受益匪浅!

关于"析构函数前加virtual"这个问题,综合大家的指点和书上的话,我想如果我理解的没有什么错误的话,它是这样子的:

//////////////////////////////////////////////////////////////////////////////////
  首先,每个派生类对象都有一个指向虚函数表的指针,访问任何虚函数都是间接通过这个指针进行的,之所以要用虚函数表,是因为调用一个虚函数的哪个版本是在运行过程(调用时指针所指的对象)才能确定的(动态绑定)。
  相对于虚函数,实函数的调用机制就简单的多:由于每个实函数只有一个版本,因此调用地址在编译时即可确定(静态绑定)

  析构函数也可以通过virtual修饰而声名为虚函数,虚析构函数与一般虚函数的不同之处在于:
  1》它的重定义函数就是派生类的析构函数,但不要求同名。
  2》一个虚析构函数的版本被调用后,接着就要调用执行基类版本,依次类推,直到调用执行了派生序列的最开始的那个虚析构函数版本为止。

//////////////////////////////////////////////////////////////////////////////////
  以上引自《全国计算机等级考试二级教程——C++语言程序设计》

也就是说,Base *p=new Derive; 产生的对象是Base的.

  当不在基类前不加virtual时,派生类的析构函数不加入虚函数表中,此时析构函数就是实函数,只有一个版本,就是对象自己的~Base();

  当基类前加virtual时,派生类和基类的析构函数都加入虚函数表中,调用析构函数的时候就调用当前指针所指的那个版本的析构函数.之后的事情:一个虚析构函数的版本被调用后,接着就要调用执行基类版本,依次类推,直到调用执行了派生序列的最开始的那个虚析构函数版本为止。

5555~ 真是不容易啊~
我想说一句——理解万岁!!太谢谢大家了!!!

最后,再麻烦大家帮忙看看上面写的有什么不对的地方^-^
回复

使用道具 举报

0

主题

5

帖子

5.00

积分

新手上路

Rank: 1

积分
5.00
发表于 2021-3-9 05:15:01 | 显示全部楼层
问这种问题一看就知道程序写得太少了
很多东西在你写程序时自然会遇到 那个时候你的理解才是最深刻的!!
回复

使用道具 举报

0

主题

1

帖子

2.00

积分

新手上路

Rank: 1

积分
2.00
发表于 2021-3-9 06:15:02 | 显示全部楼层
当基类的指针需要调用其派生类对象时,需要将基类的虚构函数声明为virtual,析构的时候才能将基类和派生类的对象析构掉
回复

使用道具 举报

0

主题

1

帖子

2.00

积分

新手上路

Rank: 1

积分
2.00
发表于 2021-3-9 07:00:02 | 显示全部楼层
呵呵,DELPHI里面的析构一直是这么干的。
回复

使用道具 举报

0

主题

55

帖子

44.00

积分

新手上路

Rank: 1

积分
44.00
发表于 2021-3-9 08:00:01 | 显示全部楼层
楼主,析构函数是不能被继承,但是编译器会自动生成析构函数(具体条件看effective c++),这个自动生产的析构函数会调用基类的析构函数。
回复

使用道具 举报

1

主题

4

帖子

5.00

积分

新手上路

Rank: 1

积分
5.00
发表于 2021-3-9 08:15:01 | 显示全部楼层
为了构造和析构配对,如果没有virtual的话,一旦出现继承,就会出现构造(子类的构造函数)和析构(父类的析构)进行配对,这是不应该出现的
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|CopyRight © 2008-2023|verysource.com ( 京ICP备17048824号-1 )

快速回复 返回顶部 返回列表