C++ 虚函数

OrzMiku / 2023-08-20 / 原文

虚函数

看下面这段代码:

#include <iostream>

using namespace std;

class Entity{
public:
    void getName(){
        cout << "Entity" << endl;
    }
};

class Player: public Entity{
private:
    string name;
public:
    Player(string t_name){
        name = t_name;
    }
    void getName(){
        cout << name << endl;
    }
};

int main()
{
    Entity *e = new Entity();
    Player *p = new Player("蔡旭村");
    p->getName(); // 正常,调用了Player重写的getName
    e->getName(); // 正常,调用了Entity的getName
    Entity *ep = p;
    // 出现异常,这里e指向p,p是Player,但是调用了Entity的getName(因为e指针是Entity的指针)
    ep->getName();
    // 这里我希望他调用到正确的函数(Player的getName(),需要使用虚函数)
    return 0;
}

Entity指针指向它的派生类Player的指针。此时调用成员方法调用的是Entity的,但是我们这里需要调用的是Player的成员方法。需要用到虚函数,程序修改后如下:

(注意 override 是C++ 11后才有的,可以不写)

#include <iostream>

using namespace std;

class Entity{
public:
    virtual void getName(){
        cout << "Entity" << endl;
    }
};

class Player: public Entity{
private:
    string name;
public:
    Player(string t_name){
        name = t_name;
    }
    void getName () override{
        cout << name << endl;
    }
};

int main()
{
    Entity *e = new Entity();
    Player *p = new Player("蔡旭村");
    p->getName(); // 正常,调用了Player重写的getName
    e->getName(); // 正常,调用了Entity的getName
    Entity *ep = p;
    ep->getName(); // 正常,调用了Player重写的getName
    return 0;
}

纯虚函数

  • 纯虚函数所在的类(接口)不能被实例化,因为这个函数没有定义。
  • 纯虚函数没有定义,函数交给派生类去定义。
  • 派生类必须实现基类中的纯虚函数。
virtual xxx funName(xxx) = 0; // 纯虚函数

Talk is cheap. Show me the code.

#include <iostream>

using namespace std;

class Api{
public:
    virtual string getClassName() = 0; // 纯虚函数
};

class Logs: public Api{
    string getClassName() override{
        return "Logs";
    }
};

class Player: public Api{
    string getClassName() override{
        return "Player";
    }
};

void printClassName(Api *p_api){
    cout << p_api->getClassName() << endl;
}

int main()
{
    Logs *console = new Logs();
    Player player;
    printClassName(console);
    printClassName(&player);
    return 0;
}

代码中 Api 类中有一个获取类名的纯虚函数。 LogsPlayer 类都继承了 Api 类。

所以 LogsPlayer 必须实现获取类名的功能。


引入原因

1、为了方便使用多态特性,我们常常需要在基类中定义虚函数。

2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎,孔雀等子类,但动物本身生成对象明显不合常理。