C++虚成员函数

在上一节中已经提到了虚函数的声明方法了,就是在函数返回类型前加上 virtual 关键字。virtual 关键字仅用于函数声明,如果函数是在类外定义,则不需要再加上 virtual 关键字了。

在 C++ 中,只有类中的成员函数能被声明为虚函数,而对于顶层函数则不能声明为虚函数。原因很简单,声明虚函数是为了构成多态,而构成多态的第一个条件就是需要继承关系,顶层函数很明显是不具有继承关系的,因此也就不能被声明为虚函数了。

【例 1】
#include<iostream>
using namespace std;

class base
{
public:
    virtual void display();
};

class derived: public base
{
public:
    virtual void display();

};

void base::display()
{
    cout<<"I'm base class!"<<endl;
}

void derived::display()
{
    cout<<"I'm derived class!"<<endl;
}

int main()
{
    base * p = new base;
    p->display();
    delete p;
    p = new derived;
    p->display();
    delete p;
    return 0;
}
在本例中,我们将两个类中的 display() 函数在类内部声明,在类外部定义,当然这么修改并不会改变程序的运行结果。需要注意的是,类内声明 display() 函数时,通过在返回值类型前添加 virtual 关键字使其成为虚函数,在类外定义时,display() 函数的返回值类型前并未添加 virtual 关键字。

另外在例 1 中,我们在基类和派生类中的 display() 函数声明时都加上了 virtual 关键字,以表示将其声明为虚函数,而实际上这是不需要的。我们只需要将基类中的 display() 函数通过 virtual 关键字声明为虚函数,即使派生类中 display() 函数声明时未注明 virtual 关键字,它在所有的派生类中都将自动成为虚函数。

【例 2】
#include<iostream>
using namespace std;

class base
{
public:
    virtual void display();
};

class derived: public base
{
public:
    void display();

};

void base::display()
{
    cout<<"I'm base class!"<<endl;
}

void derived::display()
{
    cout<<"I'm derived class!"<<endl;
}

int main()
{
    base * p = new base;
    p->display();
    delete p;
    p = new derived;
    p->display();
    delete p;
    return 0;
}
在本例中,我们将例 1 中派生类的 display() 成员函数声明时所用的 virtual 关键字去掉,编译并运行程序,结果显示程序运行结果仍然保持不变。

和普通的成员函数一样,虚成员函数同样可以被继承。

【例 3】
#include<iostream>
using namespace std;

class base
{
public:
    virtual void hello(){cout<<"Hello!"<<endl;}
};

class derived: public base
{
    //......
};

int main()
{
    base * p = new base;
    p->hello();
    delete p;
    p = new derived;
    p->hello();
    delete p;
    derived d;
    d.hello();
    return 0;
}
在本例中,派生类 derived 中无新增的成员变量或成员函数,它是 base 类的派生类。主函数中依然是定义一个 base 类的指针,并先后指向基类和派生类的对象。

由于派生类中并不存在与基类 hello() 函数具有相同函数名的虚函数,因此并未构成多态,自始至终都是调用的都是基类的 hello() 函数。之后又定义了一个派生类对象 d,这个对象调用 hello() 函数,这个 hello() 函数同样是继承自基类 base 中的 hello() 函数。从这个程序很明显可以看出虚函数是具有继承特性的,这一点它与普通函数一般无二。