C++虚函数与纯虚函数

虚函数

如果需要通过基类的指针指向派生类的对象,并访问某个与基类同名的成员,那么首先在基类中将这个同名函数声明为虚函数。这样就可以通过基类指针,使属于不同派生类的不同对象产生不同的行为,从而实现运行过程的多态。

如果你编写代码的时候,并不能确定调用的是基类的函数还是哪个派生类的函数时,你可以选择使用虚函数
即在类的定义中使用virtual关键字来限定函数成员,不过注意虚函数声明只能出现在类定义中的函数原型声明中,而不能在成员函数实现的时候。

代码如下:

#include <iostream>
using namespace std;

class Base1{               //基类Base1定义
    public:
        virtual void display() const;           //虚函数
}; 

void Base1::display() const{
    cout<<"Base1::display()"<<endl;
}

class Base2:public Base1{                      //公有派生类Base2定义
    public:
        virtual void display() const;          //覆盖基类的虚函数
}; 

void Base2::display() const{
    cout<<"Base2::display()"<<endl;
}

class Derived:public Base2{                    //公有派生类Derived定义
    public:
        virtual void display() const;          //覆盖基类的虚函数
}; 

void Derived::display() const{
    cout<<"Derived::display()"<<endl;
}

void fun(Base1 *ptr){                          //参数为指向基类对象的指针
    ptr->display();                            //“对象指针->成员名”
}

int main(){
    Base1 base1;                               //定义对象
    Base2 base2;
    Derived derived;
    fun(&base1);                               //用Base1对象的指针调用fun函数
    fun(&base2);                               //用Base2对象的指针调用fun函数
    fun(&derived);                             //用Derived对象的指针调用fun函数
    return 0;
}

注意为了清楚地提示这是一个虚函数,我在两个派生类中都使用了virtual关键字。

运行结果:
这里写图片描述
子类可以重写父类的虚函数实现子类的特殊化。
从上例看出,在fun函数中使用基类类型的指针ptr可以指向Base1,Base2还有Derived的display()函数成员,使程序更加高效简洁。

假设我把其中的virtual都去掉,运行起来就是如下的场景:
这里写图片描述
因为去掉了virtual,程序根据其是Base1的指针全部调用了Base1的display方法执行。

我来斗胆总结一下:不使用virtual,程序根据引用、指针类型选择方法;使用virtual,程序根据对象类型来选择方法。基类派生类函数名相同功能不同时最好使用virtual


纯虚函数

有时候,基类中的虚函数是为了派生类中的使用而声明定义的,其在基类中没有任何意义,此类函数我们叫做纯虚函数。带有纯虚函数的类称为抽象类。

纯虚函数与一般虚函数成员的原型书写不同,后面加了“=0”。声明为纯虚函数之后,基类就可以不再给出函数的实现部分,纯虚函数的函数体就只能交给派生类来给出了。这一点较于虚函数更好理解。

代码如下:

#include <iostream>
using namespace std;

class Base1{
    public:
        virtual void display() const=0;          //纯虚函数
}; 

class Base2:public Base1{
    public:
        virtual void display() const;            //覆盖基类的虚函数
}; 

void Base2::display() const{
    cout<<"Base2::display()"<<endl;
}

class Derived:public Base2{
    public:
        virtual void display() const;            //覆盖基类的虚函数
}; 

void Derived::display() const{
    cout<<"Derived::display()"<<endl;
}

void fun(Base1 *ptr){                          //参数为指向基类对象的指针
    ptr->display();                            //“对象指针->成员名”
}

int main(){
    Base2 base2;
    Derived derived;
    fun(&base2);
    fun(&derived);
    return 0;
}

运行结果:
这里写图片描述

程序中类Base1,Base2和Derived属于同一个类族,抽象类Base1通过纯虚函数为整个类族提供了通用外部接口。抽象类的Base1类型指针也可以指向任何一个派生类对象。在fun函数中通过基类Base1指针ptr可访问到ptr指向的派生类Base2,Derived类对象成员,这样就实现了对同一类族的对象进行统一的多态处理。

猜你喜欢

转载自blog.csdn.net/weixin_41656968/article/details/80852747