关于基类析构函数的问题

uchiha_iTachi 2013-08-10 11:45:46
有这么几个问题:
1.基类析构函数不为虚的话,用派生类指针转化为基类指针之后,删除这个基类指针时,调用的都只是基类的析构函数,是这样吗?
2.如果真的是这样,那我bear *a = new panda;delete a的时候,输出的是:
animal init...
bear init...
panda init...
bear delete...
animal delete...
为甚么animal的析构也调用了?然后是不是可以说,1的说法不是和严谨?有没有一种更严谨的说法?
3.一般情况下,是不是应该把父类的析构函数都设为虚的?比如我这个例子,除了把animal的析构设为虚之外,也应该把bear的析构设为虚?
4.我废话是不是太多了?还是说我的思维太严谨了

#include <iostream>

class animal
{
public:
animal()
{
std::cout<<"animal init..."<<std::endl;
}
//virtual
~animal()
{
std::cout<<"animal delete..."<<std::endl;
}
};

class bear : public animal
{
public:
bear()
{
std::cout<<"bear init..."<<std::endl;
}

//virtual
~bear()
{
std::cout<<"bear delete..."<<std::endl;
}
};

class panda : public bear
{
public:
panda()
{
std::cout<<"panda init..."<<std::endl;
}
~panda()
{
std::cout<<"panda delete..."<<std::endl;
}

};


int main()
{
bear *a = new panda;
//animal *a = new panda;
delete a;
}
...全文
204 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
大尾巴猫 2013-08-10
  • 打赏
  • 举报
回复
引用 2 楼 u011249050 的回复:
可以看《深入解析C++对象模型》这本书,说的很详细 用基类指针指向派生类的对象时,指针是通过要读取的内容去判断的,所以他只保留了基类的部分,通过这个指针是无法访问派生类的部分的 在delete的时候,因为基类里面有定义的析构函数,如果派生类中没有定义析构函数,会调用基类的析构函数。即使当派生类中定义了析构函数,C++也会默认把基类的析构函数添加进派生类中已定义的析构函数的。
2.如果真的是这样,那我bear *a = new panda;delete a的时候,输出的是: ------------------------------------------------------------------------- bear指针,当然调用bear的析构函数(因为bear的析构不是虚函数),然后再调用bear的基类animal的析构,但是,panda并没有析构。所以这个对象没有完整的析构,不正确。 派生类的析构,自己析构完成一定是会调用他的基类析构的。这和虚函数没关系,虚不虚都要这样一层层往上析构。 3.一般情况下,是不是应该把父类的析构函数都设为虚的?比如我这个例子,除了把animal的析构设为虚之外,也应该把bear的析构设为虚? -------------------------------------------------- 如果要用多态的特性,基类的虚函数必须要虚的,否则析构对象不完整。 不用多态的特性,则不需要虚函数,毕竟虚函数多了个查表的过程,影响些效率。 只要基类某个函数是虚的,所有继承这个基类的函数(包括继承的继承)都是虚的,不写virtual,系统默认也是virtual的 一日为虚,终身为虚。
passion_wu128 2013-08-10
  • 打赏
  • 举报
回复
一个类析构时,不管它的基类虚函数是不是virtual的,都是先析构自身再析构基类。这和构造时先构造基类再构造自身的顺序相反。 所以 bear *a = new panda; delete a; 会输出 animal init... bear init... panda init... bear delete... animal delete... 如果animal的析构函数是virtual的,就会有动态绑定。输出结果是: animal init... bear init... panda init... panda delete... bear delete... animal delete... 还有虚函数的基本知识: 只要基类函数是virtual的,派生类相应函数不管有没有virtual修饰都是vritual的.
「已注销」 2013-08-10
  • 打赏
  • 举报
回复
可以看《深入解析C++对象模型》这本书,说的很详细 用基类指针指向派生类的对象时,指针是通过要读取的内容去判断的,所以他只保留了基类的部分,通过这个指针是无法访问派生类的部分的 在delete的时候,因为基类里面有定义的析构函数,如果派生类中没有定义析构函数,会调用基类的析构函数。即使当派生类中定义了析构函数,C++也会默认把基类的析构函数添加进派生类中已定义的析构函数的。
uchiha_iTachi 2013-08-10
  • 打赏
  • 举报
回复
来人啊 帮帮忙啊
mujiok2003 2013-08-10
  • 打赏
  • 举报
回复
引用 楼主 liyuanhong13 的回复:
有这么几个问题: 1.基类析构函数不为虚的话,用派生类指针转化为基类指针之后,删除这个基类指针时,调用的都只是基类的析构函数,是这样吗?
调用的只是基类的析构函数其实应为:不会调用子类的析构函数。

A* p =...
detele p; //A及其基类的析构是会被调用,*p的动态类型的析构函数不会被调用
前提:析构函数非虚
「已注销」 2013-08-10
  • 打赏
  • 举报
回复
引用 6 楼 liyuanhong13 的回复:
[quote=引用 4 楼 ananluowei 的回复:] [quote=引用 2 楼 u011249050 的回复:] 可以看《深入解析C++对象模型》这本书,说的很详细 用基类指针指向派生类的对象时,指针是通过要读取的内容去判断的,所以他只保留了基类的部分,通过这个指针是无法访问派生类的部分的 在delete的时候,因为基类里面有定义的析构函数,如果派生类中没有定义析构函数,会调用基类的析构函数。即使当派生类中定义了析构函数,C++也会默认把基类的析构函数添加进派生类中已定义的析构函数的。
2.如果真的是这样,那我bear *a = new panda;delete a的时候,输出的是: ------------------------------------------------------------------------- bear指针,当然调用bear的析构函数(因为bear的析构不是虚函数),然后再调用bear的基类animal的析构,但是,panda并没有析构。所以这个对象没有完整的析构,不正确。 派生类的析构,自己析构完成一定是会调用他的基类析构的。这和虚函数没关系,虚不虚都要这样一层层往上析构。 3.一般情况下,是不是应该把父类的析构函数都设为虚的?比如我这个例子,除了把animal的析构设为虚之外,也应该把bear的析构设为虚? -------------------------------------------------- 如果要用多态的特性,基类的虚函数必须要虚的,否则析构对象不完整。 不用多态的特性,则不需要虚函数,毕竟虚函数多了个查表的过程,影响些效率。 只要基类某个函数是虚的,所有继承这个基类的函数(包括继承的继承)都是虚的,不写virtual,系统默认也是virtual的 一日为虚,终身为虚。[/quote]你说的我大概明白了,还有个问题,析构函数跟合成析构函数的区别是什么?析构派生类对象要先析构派生类,再依次往上析构,我就在想,创建一个派生类对象的时候,编译器是不是在这时候创建一个合成析构函数,然后释放这个派生类对象的时候,用这个合成析构函数一层层的释放,但是有看书上说,这个合成析构函数是用来释放类的成员的,然后就矛盾了东西,到底析构函数释放哪些?合成析构函数又释放哪些东西?[/quote] 这就涉及到对于类的存储方式的设计了,看《深入解析C++对象模型》没错的 析构函数不自定义的话,只有在必要的时候编译器才会产生。 在C++中基类声明的变量也会在派生类中,申请空间会一起申请,普通函数等是分配内存的地方和变量不一样,虚函数是用一个vtpr指针指向一个虚函数表来实现的。 析构派生类时,你可以想象成,基类的变量也是在派生类中声明的,所以就是先析构派生类中的东西,再析构基类中的。
大尾巴猫 2013-08-10
  • 打赏
  • 举报
回复
引用 6 楼 liyuanhong13 的回复:
你说的我大概明白了,还有个问题,析构函数跟合成析构函数的区别是什么?析构派生类对象要先析构派生类,再依次往上析构,我就在想,创建一个派生类对象的时候,编译器是不是在这时候创建一个合成析构函数,然后释放这个派生类对象的时候,用这个合成析构函数一层层的释放,但是有看书上说,这个合成析构函数是用来释放类的成员的,然后就矛盾了,到底析构函数释放哪些东西?合成析构函数又释放哪些东西?
合成析构函数的概念我不明白。 我看的书c++ prime plus中没有这个名称。 编译器具体怎么实现一层层往上析构的,我也不清楚。
uchiha_iTachi 2013-08-10
  • 打赏
  • 举报
回复
引用 4 楼 ananluowei 的回复:
[quote=引用 2 楼 u011249050 的回复:] 可以看《深入解析C++对象模型》这本书,说的很详细 用基类指针指向派生类的对象时,指针是通过要读取的内容去判断的,所以他只保留了基类的部分,通过这个指针是无法访问派生类的部分的 在delete的时候,因为基类里面有定义的析构函数,如果派生类中没有定义析构函数,会调用基类的析构函数。即使当派生类中定义了析构函数,C++也会默认把基类的析构函数添加进派生类中已定义的析构函数的。
2.如果真的是这样,那我bear *a = new panda;delete a的时候,输出的是: ------------------------------------------------------------------------- bear指针,当然调用bear的析构函数(因为bear的析构不是虚函数),然后再调用bear的基类animal的析构,但是,panda并没有析构。所以这个对象没有完整的析构,不正确。 派生类的析构,自己析构完成一定是会调用他的基类析构的。这和虚函数没关系,虚不虚都要这样一层层往上析构。 3.一般情况下,是不是应该把父类的析构函数都设为虚的?比如我这个例子,除了把animal的析构设为虚之外,也应该把bear的析构设为虚? -------------------------------------------------- 如果要用多态的特性,基类的虚函数必须要虚的,否则析构对象不完整。 不用多态的特性,则不需要虚函数,毕竟虚函数多了个查表的过程,影响些效率。 只要基类某个函数是虚的,所有继承这个基类的函数(包括继承的继承)都是虚的,不写virtual,系统默认也是virtual的 一日为虚,终身为虚。[/quote]你说的我大概明白了,还有个问题,析构函数跟合成析构函数的区别是什么?析构派生类对象要先析构派生类,再依次往上析构,我就在想,创建一个派生类对象的时候,编译器是不是在这时候创建一个合成析构函数,然后释放这个派生类对象的时候,用这个合成析构函数一层层的释放,但是有看书上说,这个合成析构函数是用来释放类的成员的,然后就矛盾了,到底析构函数释放哪些东西?合成析构函数又释放哪些东西?
大尾巴猫 2013-08-10
  • 打赏
  • 举报
回复
#4 有个小地方手误,更正一下 如果要用多态的特性,基类的虚函数必须要虚的,否则析构对象不完整。 改为 析构函数

64,685

社区成员

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

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