C++ 编译器如何知道要调用哪个虚函数实现?

2022-01-24 00:00:00 oop polymorphism c++

这是一个来自 http://www.cplusplus.com/doc 的多态性示例/tutorial/polymorphism.html(为便于阅读而编辑):

Here is an example of polymorphism from http://www.cplusplus.com/doc/tutorial/polymorphism.html (edited for readability):

// abstract base class
#include <iostream>
using namespace std;

class Polygon {
    protected:
        int width;
        int height;
    public:
        void set_values(int a, int b) { width = a; height = b; }
        virtual int area(void) =0;
};

class Rectangle: public Polygon {
    public:
        int area(void) { return width * height; }
};

class Triangle: public Polygon {
    public:
        int area(void) { return width * height / 2; }
};

int main () {
    Rectangle rect;
    Triangle trgl;
    Polygon * ppoly1 = &rect;
    Polygon * ppoly2 = &trgl;
    ppoly1->set_values (4,5);
    ppoly2->set_values (4,5);
    cout << ppoly1->area() << endl; // outputs 20
    cout << ppoly2->area() << endl; // outputs 10
    return 0;
}

我的问题是编译器如何知道 ppoly1 是一个 Rectangle 而 ppoly2 是一个三角形,以便它可以调用正确的 area() 函数?它可以通过查看Polygon * ppoly1 = ▭"来发现这一点line 并且知道 rect 是一个 Rectangle,但这并不适用于所有情况,不是吗?如果你做了这样的事情怎么办?

My question is how does the compiler know that ppoly1 is a Rectangle and that ppoly2 is a Triangle, so that it can call the correct area() function? It could find that out by looking at the "Polygon * ppoly1 = ▭" line and knowing that rect is a Rectangle, but that wouldn't work in all cases, would it? What if you did something like this?

cout << ((Polygon *)0x12345678)->area() << endl;

假设您被允许访问该随机内存区域.

Assuming that you're allowed to access that random area of memory.

我会对此进行测试,但我目前无法在我使用的计算机上进行测试.

I would test this out but I can't on the computer I'm on at the moment.

(我希望我没有遗漏一些明显的东西......)

(I hope I'm not missing something obvious...)

推荐答案

每个对象(属于具有至少一个虚函数的类)都有一个指针,称为 vptr.它指向其实际类的 vtbl(每个具有虚函数的类至少有一个;对于某些多重继承场景可能不止一个).

Each object (that belongs to a class with at least one virtual function) has a pointer, called a vptr. It points to the vtbl of its actual class (which each class with virtual functions has at least one of; possibly more than one for some multiple-inheritance scenarios).

vtbl 包含一堆指针,每个指针对应一个虚函数.所以在运行时,代码只是使用对象的 vptr 来定位 vtbl,并从那里找到实际重写函数的地址.

The vtbl contains a bunch of pointers, one for each virtual function. So at runtime, the code just uses the object's vptr to locate the vtbl, and from there the address of the actual overridden function.

在您的特定情况下,PolygonRectangleTriangle 每个都有一个 vtbl,每个都有一个指向其相关 area 方法的入口.您的 ppoly1 将有一个 vptr 指向 Rectanglevtblppoly2Trianglevtbl 类似.希望这会有所帮助!

In your specific case, Polygon, Rectangle, and Triangle each has a vtbl, each with one entry pointing to its relevant area method. Your ppoly1 will have a vptr pointing to Rectangle's vtbl, and ppoly2 similarly with Triangle's vtbl. Hope this helps!

相关文章