我在Wikipedia读了一篇关于虚拟桌子的文章。
class B1
{
public:
void f0() {}
virtual void f1() {}
int int_in_b1;
};
class B2
{
public:
virtual void f2() {}
int int_in_b2;
};
used to derive the following class:
class D : public B1, public B2
{
public:
void d() {}
void f2() {} // override B2::f2()
int int_in_d;
};
阅读之后,我不禁想知道如何在C ++中实现非虚拟成员函数。是否有一个单独的表,如v-table,其中存储了所有函数地址?如果是,那么这个表被调用了什么以及继承期间会发生什么?
如果没有,那么编译器如何理解这些陈述?
D * d1 = new D;
d1->f0(); // statement 1
编译器如何解释f0()是B1的函数,并且由于D公开继承了D,它可以访问f0()。根据文章,编译器将语句1更改为
(*B1::f0)(d)
答案 0 :(得分:7)
非虚拟成员函数的实现类似于接受隐藏this
参数的全局函数。编译器在编译时知道基于继承树调用哪个方法,因此不需要运行时表。
答案 1 :(得分:1)
除this之外,我只能说普通成员函数只是一个类中的内存地址(我甚至认为该类的每个对象在内存中使用相同的“函数指针”,但是自己的变量)。 v表是运行时重定向的一种形式,因为编译器无法知道它正在处理的究竟的对象(显然是由于多态性)。
答案 2 :(得分:1)
是否有一个单独的表,如v-table,其中存储了所有函数地址?
它们存储在调用它们的位置。
举个例子:只要 f0 方法是非虚拟的,编译器就知道它的地址是什么,因为只有一种可能性。设地址为0xABCD。然后代码
d1->f0(); // statement 1
编译为说明:
// push onto the stack 'this' pointer, as you pointed out the address must
// be earlier translated from D class to B1 which is not presented here
push d1
call 0xABCD // call method at known address (jump to this address)