A作为基类,B作为派生类:
基类指针指向派生类(对象):
在c++中,基类的析构函数需要定义为虚函数,原因有以下几点:
当使用多态特性,让基类指针指向派生类时(不是指向 B people 定义来的people这种对象详细看下文代码),如果析构函数不是虚函数,通过基类指针销毁派生类对象时(delete pa),会调用静态绑定的析构函数,也就是基类的析构函数,从而只能销毁属于基类的元素,导致派生类析构不完全,程序就会出现资源泄露或未定义行为。
不加virtual的基类析构函数:
class A
{
public:
virtual void Play()
{;}
A()
{
cout<<"构造A"<<endl;
}
~A()
{
cout<<"A析构"<<endl;
}
};
class B : public A
{
public:
void Play()
{
cout<<"B"<<endl;
}
B()
{
cout<<"构造B"<<endl;
}
~B()
{
cout<<"B析构"<<endl;
}
};
这里的结果证明派生类没有析构,也就是说如果此时B类中有动态空间成员内存将不会被释放。
将基类析构函数设置为虚函数之后就是这样的:
但是你不将基类析构函数设置为虚函数,通过具体对象自动析构也不会出现问题,只有你通过基类指针删除才会出现问题:
运行结果:
派生类指针指向基类对象:
注:从pa=&b,这里可看出,解释一下:这里取得是b的首地址,而pa的长度是由数据类型的内存所占大小决定的,也就是A类的大小;
pb=&a的话是会报错的,因为pb的长度(下方红色箭头范围)已经超出了A(上方红色箭头范围)的内存范围,多出的那一部分可能会乱指,导致安全性缺失。
pb是派生类指针,pb本身的大小在定义时(B *pb)已经决定了它就比A类的具体对象"a"大,所以如果用派生类指针pb指向基类的"a"会导致pb空出一部分空间没有指向(指针必须有所指向),导致上文说的“安全性缺失”。
总结:派生类指针不能指向基类对象。
附录:
基类指针指向派生类(对象)B类中有动态空间成员的情况:
#include <iostream>
#include <cstring>
using namespace std;
class A
{
public:
virtual void Play()
{;}
A()
{
cout<<"构造A"<<endl;
}
~A()
{
cout<<"A析构"<<endl;
}
};
class B : public A
{
public:
char *pname;
B(char *a)
{
pname = new char(strlen(a)+1);
strcpy(pname,a);
cout<<"构造B"<<endl;
}
~B()
{
delete pname;
cout<<"B析构"<<endl;
}
void Play()
{
cout<<pname<<endl;
}
};
int main()
{
A *pa = new B("zhangsan");
pa->Play();
delete pa;
}
运行结果:
B的pname内存没有释放。