Skip to the content.

028-虚函数

看这段代码

public class Entity {
    public String getName() {
        return "Entity";
    }
}
public class Player extends Entity {

    private final String mName;

    public Player(String name) {
        this.mName = name;
    }

    public String getName() {
        return mName;
    }
}

public class Main {
    public static void main(String[] args) {
        Entity entity = new Entity();
        System.out.println(entity.getName());
        Player player = new Player("Player");
        System.out.println(player.getName());
        Entity pn = player;
        System.out.println(pn.getName());
    }
}

我们在Java中写下这样的代码,因为多态,我们运行的时候,即使父类引用指向子类的实例,调用方法的时候,依然会调用子类的实现

Entity
Player
Player

进程已结束,退出代码为 0

当我们在C++中写下这样的代码

#include <iostream>

class Entity {
public:
    std::string getName() {
        return "Entity";
    }
};

class Player : public Entity {
private:
    std::string mName;
public:
    Player(const std::string &name) : mName(name) {}

    std::string getName() {
        return mName;
    }
};

int main() {
    Entity *entity = new Entity();
    std::cout << entity->getName() << std::endl;
    Player *player = new Player("Player");
    std::cout << player->getName() << std::endl;
    Entity *pn = player;
    std::cout << pn->getName() << std::endl;
    return 0;
}

运行的时候,结果是这样的

F:\Projects\ClionProjects\test\cmake-build-debug-cygwin\test.exe
Entity
Player
Entity

这就出问题了,因为我们声明函数的时候,通常是在类的内部起作用,调用的时候,会调用属于这种类型的方法

于是,出现了虚函数,引入了一种叫动态联编(Dynamic Dispatch)的东西,他通常使用v表来实现编译,v表是一个表,他包含基类所有虚函数的映射,在运行的时候,将它们映射到正确的覆写函数上,这里,我们只需要知道,需要覆写函数的时候,必须将基类的基函数声明为虚函数,要不会出错。

声明方式就是,添加virtual即可,同时,我们可以为覆写的方法添加override,(类似Java的注解?)

class Entity {
public:
    virtual std::string getName() {
        return "Entity";
    }
};

class Player : public Entity {
private:
    std::string mName;
public:
    Player(const std::string &name) : mName(name) {}

    std::string getName() override {
        return mName;
    }
};

使用虚函数有两点额外开销

1.需要额外的内存来保存v表,基类中还有一个额外的成员指针,指向v表

2.每次调用的时候,都需要遍历v表,来确定需要映射哪个函数

其实这两点实际使用中应该没啥影响...

https://www.bilibili.com/video/BV12p4y1q7MY