基类指针就只能访问到基类函数
子类指针就只能访问到子类函数
要使用基类访问到子类的函数, 最符合常规的, 就是虚函数了.
当然, 你也可以使用非常规的, 比如强制转换, 比如自己计算函数地址并调用.
正常情况,子类祖先类的析构函数都是虚拟的,这样删除祖先类指针、子类对象的时候,可正确同时调用子类和祖先类的析构函数):
#include <iostream>
using namespace std;
class Base_J
{
public:
Base_J()
{
cout << "Base Created" << endl;
}
~Base_J()
{
cout << "Base Destroyed" << endl;
}
};
class Derived_J : public Base_J
{
public:
Derived_J()
{
cout << "Derived Created" << endl;
}
~Derived_J()
{
cout << "Derived Destroyed" << endl;
}
};
int main()
{
Base_J *pB = new Derived_J();//基类指针指向子类对象
delete pB;
pB = NULL;
system("pause");
return 0;
}
下面是它的运行结果:
上述结果比较诡异,按理说每个创建的类中的内容都应该在不用时被销毁,但是上述只是销毁了子类对象中属于父类的部分,这是什么原因呢?
先看一下几个结论:
纯虚拟函数:
《Effective C++》条款 07 p40:为多态基类声明virtual析构函数
《C++ Primer 5》 p527:在C++语言中,当我们使用基类的引用(或指针)调用一个虚函数时将发生动态绑定。
另外,Effective C++中有关于动态多态(运行时的多态:虚函数)和静态多态(编译时的多态:模板)的说明。
现在我们将基类的析构改成虚函数试试:
class Base_J
{
public:
Base_J()
{
cout << "Base Created" << endl;
}
virtual ~Base_J()
{
cout << "Base Destroyed" << endl;
}
};
结果便按照我们设想的执行了:
派生类构造函数和析构函数的执行顺序
当创建对象时,编译系统会自动调用构造函数。当撤销对象时,编译系统会自动调用析构函数。当创建派生类的对象时,首先执行基类的构造函数,然后执行派生类的构造函数。当撤销对象时,则先执行派生类的析构函数,然后再执行基类的析构函数。
《Effective C++》条款 07 p44:
- 带多态性质的base classes应该声明一个virtual析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数
- Classes的设计目的如果不是作为base classes 使用,或不是为了具备多态性,就不该声明virtual析构函数。
父类指针指向子类对象,而子类对象却经由父类指针被删除,当父类有个non-virtual析构函数是,就会引起灾难。
C++明确指出,当子类对象经由一个父类指针被删除,而该父类带有一个non-virtual析构函数,其结果未定义--实际执行时通常发生的是对象的derived成分没有被销毁。子类的析构函数也未能被执行。然而其base class成分通常会被销毁,于是造成了诡异的“局部销毁”对象。这可能造成资源泄露,败坏数据结构等