如果我们有这个代码:
class Base
{
int anint;
float afloat;
};
class Derived : Base
{
//inherited member variables...
};
我被告知Base
的成员将继承到Derived
,而Derived
中的继承成员实际上位于Base
的基类子对象内(但是这个子对象是未命名的);在Derived中创建了Base
的子对象,用于保存继承的成员。因此,当访问类中的成员时,除非您显式执行某些操作,否则会对this指针进行隐式调用,但是在访问继承对象时是否还有一个隐式指针(或任何内容)?就像,如果我们通过anint
在Derived
的实例中访问derivedInstance->anint
,这实际上看起来像derivedInstance->this->somethingToBaseObjectThatHoldsTheMembers->anint
或者这是如何工作的?
答案 0 :(得分:1)
没有指向基类数据的特殊指针。 C ++中的数据成员布局紧跟C语言。(事实上,您的示例没有虚拟方法,因此必须完全遵循C)。因此,让我们考虑您的代码在C中的外观:
struct Base
{
int anint;
float afloat;
};
struct Derived
{
struct Base; // C style inherit from struct Base
int a2ndInt;
};
在C中,结构内存布局被定义为与编写它时非常相似。这意味着struct Derived基本上具有以下内存布局。
struct Derived
{
int anint;
float afloat;
int a2ndInt;
};
此指针指向结构的开头,因此从指向Derived或Base的指针访问 anint 或 afloat 涉及相同的内存偏移。因此,羽绒在这里总是很容易。
当你拥有虚函数时,事情会变得更复杂,因为数据结构必须有一个指向其虚函数的隐藏指针,但只需要一个这样的指针。让我们考虑单继承的情况,你可以想象一个类似的布局(实际布局取决于ABI):
struct Base
{
<ABI defined pointer type> * class_; // hidden virtual function table
int anint;
float afloat;
};
struct Derived
{
struct Base; // inherit from struct Base
int a2ndInt;
};
现在struct Derived可能具有以下内存布局。请注意,在创建Derived对象时,构造函数必须设置 class _ 指针。这是构造函数从Base类构造函数开始的一个原因,因为每个Derived类都可以覆盖 class _ 指针。
struct Derived
{
<ABI defined pointer type> * class_;
int anint;
float afloat;
int a2ndInt;
};
再次从指向Derived或Base的指针访问 anint 或 afloat 涉及相同的偏移量。因此,向下铸造在这里也很容易。
多重继承要复杂得多,而且static_cast&lt;&gt;羽绒铸造是必不可少的。这种情况最接近你的想法,但仍然只涉及到一个这个指针的偏移量。
struct Base1
{
<ABI defined pointer type> * class_; // hidden virtual function table
int anint;
};
struct Base2
{
<ABI defined pointer type> * class_; // hidden virtual function table
float afloat;
};
我对ABI不太熟悉,但我想隐藏的虚拟表指针可能以某种方式合并,导致内存布局如下:
struct Derived
{
<ABI defined pointer type> * class_; // merged Base1 and Base2
int anint;
float afloat;
int a2ndInt;
};
或未合并(取决于ABI)
struct Derived
{
<ABI defined pointer type> * class_; // from Base1
int anint;
<ABI defined pointer type> * class_; // from Base2
float afloat;
int a2ndInt;
};
因此,再次从指向Derived或Base1的指针访问 anint 涉及相同的偏移量,但访问漂浮不起作用。这意味着使用从Derived指针到Base2指针的C样式转换(即使用(Base2*)
)失败,您需要static_cast<>
来处理偏移量的变化。
请注意,如果只有一个基类具有成员数据,则这并不复杂。这就是为什么经常建议在使用多重继承时,只有一个基类应该有数据。
注意:真正的ABI定义了结构中数据的真实布局。此处显示的内容仅用于说明目的。
答案 1 :(得分:-1)
没有。编译器选择布局(ABI)。静态强制转换利用该布局的知识来使用static_cast
来调整指针。
RTTI使用dynamic_cast
启用动态指针调整。