我在学习C++11中的继承,发现如果派生类重新定义了虚函数名但原型不同,则分配了指向派生类的指针的基类指针只能访问基类版本的功能。无法访问派生版本功能。我想知道为什么会这样。
class Enemy {
public:
virtual void describe() { std::cout << "Enemy"; }
};
class Dragon : public Enemy {
public:
virtual void describe(int dummy) { std::cout << "Dragon"; }
};
在main
,
Dragon foo;
Enemy* pe = &foo;
pe->describe(); // Enemy
foo.describe(1); // Dragon
pe->describe(1); // no matching function, candidate is Enemy::describe()
根据我对虚函数表的了解,pe
指向 (ie foo
) 的派生对象应该有一个指向Dragon
的 vtable 的 vpointer 成员。我也知道在派生类中重新定义函数名会隐藏基类中的所有同名函数。所以在 Dragon 的 vtable 中,“describe”的地址应该是带有参数的函数int dummy
。
但事实证明,pe
可以访问Enemy
该方法的版本,这应该是隐藏的。并且pe
无法访问Dragon
该方法的版本,该版本应该在pe
的 vtable 中。它的执行就像使用了Enemy
' 的 vtable 一样。为什么会发生这种情况?
更新:我想现在我或多或少地了解了它背后的机制。这是我的假设:
由于它是指向 的指针Enemy
,因此程序将首先在Enemy
' 范围内找到方法名称。如果未找到该名称,编译器将给出错误。如果它不是虚拟的,则调用它。如果是虚拟的,则将方法的偏移量记录在Enemy
的 vtable 中。然后程序使用这个偏移量来访问目标对象的 vtable 中的正确方法。
如果该方法被正确覆盖,则目标对象的 vtable 中该偏移量处的函数地址将被更改。否则,它将与Enemy
的 vtable 中的函数地址相同,如示例中所示。
由于Dragon
's describe
with是一个不同的原型,它在它从 Enemy 继承的原始int dummy
原型之后添加到Dragon
's vtable 中。describe
但是int dummy
无法访问该版本,Enemy*
因为Enemy
' 的 vtable 甚至没有那个偏移量。
这个对吗?