6

我正在阅读Don Clugston 在 Codeproject 上的一篇文章。这是一篇漂亮的文章,很有名。在下面的代码片段中,我发现一个特定的概念非常难以理解:

class A {
 public:
       virtual int Afunc() { return 2; };
};

class B {
 public: 
      int Bfunc() { return 3; };
};

// C is a single inheritance class, derives only from A
class C: public A {
 public: 
     int Cfunc() { return 4; };
};

// D uses multiple inheritance
class D: public A, public B {
 public: 
    int Dfunc() { return 5; };
};

该片段后面是以下段落:

假设我们为 C 类创建了一个成员函数指针。在这个例子中,Afunc 和 Cfunc 都是 C 的成员函数,所以我们的成员函数指针可以指向 Afunc 或 Cfunc。但是 Afunc 需要一个指向 C::A(我称之为 Athis)的 this 指针,而 Cfunc 需要一个指向 C(我称之为 Cthis)的 this 指针。编译器编写者通过一个技巧来处理这种情况:他们确保 A 在物理上存储在 C 的开头。这意味着 Athis == Cthis。我们只有一个需要担心,世界一切都很好。

我想了解的唯一一件事是上一段中粗体和斜体的行。

我不完全理解Afunc 需要一个指向 C::A的指针,而Cfunc 需要一个指向 C 的指针是很自然的。

任何帮助,将不胜感激。

4

1 回答 1

9

通过在 C++ 中调用成员函数,内部发生的事情是实例作为隐藏的第一个参数传递(但请注意,此行为是严格的实现定义的行为。C++ 标准对此主题无话可说,它只是一个非常常见的实现方式):

x.f(y); // is treated internally as:
f(&x, y);

然后可以通过this指针获得第一个参数。

现在,Afunc在上面的示例中,内部有签名void Afunc(A* const this),而CFunc有内部签名void CFunc(C* const this)

请注意,两种情况下的参数类型是不同的,因此当您在同一个对象上调用函数时,必须传递不同的指针。C++ 通过定义从任何派生对象到其基础对象的隐式转换来解决这个问题。也就是说,在以下代码中:

C* pc = something;
pc->Afunc();

此代码在内部的处理方式类似于以下(伪代码):

C* pc = something;
Afunc(static_cast<A*>(pc));

对于单继承,这种强制转换是通过引用中提到的技巧进行的无操作(即可以将其删除):C对象及其父A对象存储在相同的物理地址中。C存储在内存中某个地址的类型对象的x物理布局方式是,其父类型对象A存储在该地址x,然后是C可能具有的所有其他成员(但在您的情况下,它具有没有成员,并且sizeof(C) == sizeof(A))。

于 2012-06-12T09:30:22.263 回答