0

如果我们有这个代码:

class Base
{
int anint;
float afloat;
};
class Derived : Base
{
//inherited member variables...
};

有人告诉我, 的成员Base将被继承,Derived而这些继承的成员Derived实际上是在一个基类子对象中Base(但这个子对象是未命名的);的子对象Base在 Derived 中创建,其中包含继承的成员。因此,当访问类中的成员时,除非您显式执行某些操作,否则会隐式调用 this 指针,但是在访问继承对象时是否还会调用隐式指针(或任何东西)?就像,如果我们在byanint的实例中访问,这实际上会是什么样子或者它是如何工作的?DerivedderivedInstance->anintderivedInstance->this->somethingToBaseObjectThatHoldsTheMembers->anint

4

2 回答 2

1

没有指向基类数据的特殊指针。C++ 中数据成员的布局与 C 密切相关。(事实上,您的示例没有虚拟方法,因此必须完全遵循 C)。因此,让我们考虑一下您的代码在 C 中的外观:

 struct Base
 {
    int anint;
    float afloat;
 };
 struct Derived
 {
   struct Base; // C style inherit from struct Base
   int a2ndInt;
 };

在 C 中,结构内存布局被定义为与您编写它时几乎一样。这意味着结构 Derived 基本上具有以下内存布局。

struct Derived
{
    int anint;
    float afloat;
    int a2ndInt;
};

this指针指向结构的开头,因此从指向 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_指针。这是构造函数从基类构造函数开始的原因之一,因为每个派生类都可以覆盖class_指针。

struct Derived
{
    <ABI defined pointer type> * class_; 
    int anint;
    float afloat;
    int a2ndInt;
};

因此,再次从指向 Derived 或 Base 的指针访问anintafloat涉及相同的偏移量。因此向下铸造在这里又很容易。

多重继承要复杂得多,这也是向下转换的 static_cast<> 必不可少的地方。这种情况最接近您的想法,但仍然只涉及到单个this指针的偏移量。

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涉及相同的偏移量,但访问浮点数不起作用。这意味着使用(Base2*)从派生指针到 Base2 指针的 C 样式转换(即使用)失败,您需要static_cast<>处理偏移量的变化。

请注意,如果只有一个基类具有成员数据,这并不是那么复杂。这就是为什么经常建议在使用多重继承时,只有一个基类应该有数据。

注意:真正的 ABI 定义了结构中数据的真实布局。此处显示的内容仅用于说明目的。

于 2017-09-19T10:09:05.190 回答
-1

不,编译器选择了一个布局 (ABI)。静态转换利用该布局的知识来调整使用static_cast.

RTTI 启用动态指针调整,使用dynamic_cast.

参见例如Regular cast vs. static_cast vs. dynamic_cast

于 2017-09-18T13:26:07.873 回答