虚函数在应用中主要分为两大方面,一方面是虚析构函数,另一方面是虚函数,请记住没有虚构造函数。
一、虚析构函数:
virtual ~Dwelling();
class Dwelling
{
public:
...
};
class Hovel:public Dwelling
{
public:
...
};
此刻假如我们定义了一个指向基类的指针或引用的派生类对象,这个时候基类中的析构函数就需要改写成虚析构函数了。例如:
Hovel *p=new Dwelling();
当我们派生类对象调用完毕,即将销毁所占用的内存空间时,我们可能构造派生类中的析构函数,才能正确销毁p,如下:
~Hovel()
{
delete (Dweeling*)p;
}
但是有时候我们并不是很清楚我们需要销毁的指针或引用p的类型,或者说为了方便起见,我们可以直接将基类中析构函数定义为虚函数,这样子在派生类执行析构函数时将会直接调用基类中的虚析构函数进行撤销对象所占用的空间。
二、虚函数
class Dwelling
{
public:
virtual void showperks(int a) const;
...
};
class Hovel:public Dwelling
{
public:
virtual void showperks () const;
...
};
请注意看上面代码中的两个虚函数名称完全一致,只是传参不同,如此的话派生类对象在调用基类方法的时候,只能够调用到最近的方法(即派生类中方法,基类中的方法将被自动屏蔽掉),如下:
Hovel trump;
trump.showperks(); //valid
trump.showperks(5); //invalid
总之,重新定义继承的方法并不是重载,如果重新定义派生类中的函数,而函数只要虚基类中的方法同名(同名即可,无论参数列表是否一致),基类中的所有同名方法将会被自动屏蔽,因此如果需要重新定义基类中的方法的话,需要全部重新定义,如下:
class Dwelling
{
public:
virtual void showperks(int a) const;
virtual void showperks(double x) const;
virtual void showperks() const;
...
};
class Hovel:public Dwelling
{
/*则此处的方法需要全部重新定义,哪怕只有其中一个发生了改变*/
public:
virtual void showperks(int a) const;
virtual void showperks(double x) const;
virtual void showperks() const;
...
};
不过还好,如果重新定义的方法并不改变,我们可以这么去定义它:
void Hovel::showperks() const
{
Dwelling::showperks();
}
例外:
如果重新定义继承的方法,应确保与原来的原型完全相同,但如果返回类型是基类引用或指针,则可以修改为指向派生类的引用或指针,但这种例外只适用于返回值,不适用于参数。
class Dwelling
{
public:
virtual Dwelling & showperks(int a) const;
...
};
class Hovel:public Dwelling
{
public:
virtual Hovel & showperks(int a) const;
...
};