【发布时间】:2013-04-10 09:00:08
【问题描述】:
看下面的C++代码
class Base1 {
public:
Base1();
virtual ~Base1();
virtual void speakClearly();
virtual Base1 *clone() const;
protected:
float data_Base1;
};
class Base2 {
public:
Base2();
virtual ~Base2();
virtual void mumble();
virtual Base2 *clone() const;
protected:
float data_Base2;
};
class Derived : public Base1, public Base2 {
public:
Derived();
virtual ~Derived();
virtual Derived *clone() const;
protected:
float data_Derived;
};
《C++对象模型内幕》4.2说Base1、Base2和Derived类的虚表布局是这样的:
我的问题是:
Derived 类的 Base1 子对象的虚拟表包含Base2::mumble。为什么?我知道 Derived 类与 Base1 共享了这个虚拟表,所以我认为 Base2 的功能不应该出现在这里。有人能告诉我为什么吗?谢谢。
【问题讨论】:
-
在
Derivedvtable 的Base1之后添加额外的条目并没有什么坏处。可以这样做是为了提高效率。给定一个Derived*指针,通过Base1/Derivedvtable 调用虚函数比通过Base2vtable 更便宜。 -
注意:事情的呈现方式似乎搞砸了,在 Itanium ABI 中,
_vptr成员实际上是first;同样Base1是Derived的first 成员。 -
@MatthieuM。在我见过的所有编译器中,
_vptr(伪)成员一直是类中的第一件事,但标准显然允许它在任何地方使用。 -
@JamesKanze:是的,这就是为什么我要准确地说我正在谈论的 ABI(这也是我唯一稍微熟悉的 ABI);但在我看来,要使优化相关,您希望尽可能轻松地找到
Base1(以及_vptr)的地址;理想情况下不涉及算术。 -
@MatthieuM。您希望尽可能轻松地找到所有
_vptr的地址:-)。说真的,对于英特尔来说,有一个论点是将_vptr放在第一个基类的末尾,并维护一个指向 it 的指针作为指向对象的指针。 (没有规则,或者至少以前没有,Derived*必须指向对象的第一个字节。)英特尔有一种寻址模式,其中基指针的偏移量可能是单个字节,在-128...127的范围内。把指向对象的指针放到对象的中间意味着可以多用这个。