1. 构造函数
因为在派生类中构造函数是不能继承的,也没有重定义的必要。在构造函数中调用虚函数将破坏动态绑定逻辑。下面的例子说明了这样动态绑定逻辑。
例:
#include<iostream.h>
class base
{
protected:
int x;
public:
base (int m)
{
x=m+1;
print( );
}
virtual void print( )
{
cout<<”The virtual function in base is called!”<<endl;
cout<<x<<endl;
}
};
class derive: public base
{
private:
int y;
public:
derive (int m): base(m)
{
y=m;
print( );
}
virtual void print( )
{
cout<<”The virtual function in derive is called!”<<endl;
cout<<y<<endl;
}
};
void main( )
{
derive obj(10);
}
程序的输出结果为:
The virtual function in base is called!
11
The virtual function in derive is called!
10
程序从创建派生类的对象开始执行,在执行中,先要调用基类的构造函数。此时派生类的创建过程尚未完成,只能按静态绑定调用基类的虚函数,无法实现预期的多态逻辑。
请记住:
在构造和析构期间不要调用virtual 函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层)。
如果在构造函数或析构函数中调用虚函数,则运行的是为构造函数或析构函数自身类型定义的版本。可以理解为:在base class 构造期间, virtual 函数不是virtual 函数。
2.虚析构函数
析构函数可以通过virtual修饰而声明为虚析构函数。虚析构函数与一般虚函数的不同之处在于:
(1)覆盖虚析构函数的重定义函数就是派生类的析构函数,不要求同名;
(2)虚析构函数由系统自动调用;
(3)一个虚析构函数的版本被调用后,接着就要调用被它覆盖的基类版本,依次类推,直到调用了派生序列的根类的析构函数版本为止。
为什么析构函数为虚?
在处理继承层次中的对象时,指针的静态类型可能与被删除对象的动态类型不同。因此基类中的析构函数必须为虚函数(虚函数特性会被继承,派生类的析构函数也是虚的)。
Base *pBase = new Derived;
delete pBase;
如果Base的析构函数不为虚,删除指针时只会执行Base的析构函数,造成内存泄漏;反之,则先析构Derived,再析构Base。
例:
#include<iostream.h>
class base
{
public:
virtual void say( )
{
cout<<”I am base.”<<endl;
}
~base( )
{
cout<<”Delete object of
base”<<endl;
}
};
class derived:public base
{
public:
virtual void say( )
{
cout<<”I am derived”<<endl;
}
~derived( )
{
cout<<”Delete object of derived”<<endl;
};
void main( )
{
base *p1=new derived;
p1->say( );
delete p1;
}
程序的输出结果为:
I am derived
Delete object of derived
显然,p1->say( )语句正确地动态绑定了派生类中的重载代码,delete p1语句也正确地释放了为p1分配的内存空间。 但是,base*p1=new derived 语句执行时,先创建了一个指向base类对象的指针p1,然后又创建了一个derived类的动态对象,最后再让p1指向derived的对象。所以delete p1执行时应调用base和derived两个类的构造函数。
由于该程序定义的多态性中没有将析构函数用virtual关键字说明,
delete p1的执行是不正确的。
将
析构函数加上virtual
关键字说明,重新运行程序将得到以下正确结果:
I am derived
Delete object of derived
Delete object of base
请记住:
• polymorphic (带多态性质的) base classes 应该声明一个virtual 析构函数。如果class 带有任何virtual 函数,它就应该拥有一个virtual 析构函数。
• Classes 的设计目的如果不是作为base classes 使用,或不是为了具备多态性(polymorphically) ,就不该声明virtual 析构函数。
• polymorphic (带多态性质的) base classes 应该声明一个virtual 析构函数。如果class 带有任何virtual 函数,它就应该拥有一个virtual 析构函数。
• Classes 的设计目的如果不是作为base classes 使用,或不是为了具备多态性(polymorphically) ,就不该声明virtual 析构函数。