关于基类析构函数的问题
有这么几个问题:
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;
}
------解决方案--------------------
可以看《深入解析C++对象模型》这本书,说的很详细
用基类指针指向派生类的对象时,指针是通过要读取的内容去判断的,所以他只保留了基类的部分,通过这个指针是无法访问派生类的部分的
在delete的时候,因为基类里面有定义的析构函数,如果派生类中没有定义析构函数,会调用基类的析构函数。即使当派生类中定义了析构函数,C++也会默认把基类的析构函数添加进派生类中已定义的析构函数的。
[解决办法]
一个类析构时,不管它的基类虚函数是不是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的.
[解决办法]
2.如果真的是这样,那我bear *a = new panda;delete a的时候,输出的是:
-------------------------------------
bear指针,当然调用bear的析构函数(因为bear的析构不是虚函数),然后再调用bear的基类animal的析构,但是,panda并没有析构。所以这个对象没有完整的析构,不正确。
派生类的析构,自己析构完成一定是会调用他的基类析构的。这和虚函数没关系,虚不虚都要这样一层层往上析构。
3.一般情况下,是不是应该把父类的析构函数都设为虚的?比如我这个例子,除了把animal的析构设为虚之外,也应该把bear的析构设为虚?
--------------------------------------------------
如果要用多态的特性,基类的虚函数必须要虚的,否则析构对象不完整。
不用多态的特性,则不需要虚函数,毕竟虚函数多了个查表的过程,影响些效率。
只要基类某个函数是虚的,所有继承这个基类的函数(包括继承的继承)都是虚的,不写virtual,系统默认也是virtual的
一日为虚,终身为虚。
[解决办法]
调用的只是基类的析构函数其实应为:不会调用子类的析构函数。
A* p =...
detele p; //A及其基类的析构是会被调用,*p的动态类型的析构函数不会被调用
前提:析构函数非虚