2

I was reading about the C++ Objects when I got this doubt. Suppose there are two classes

class X
{
     virtual int def() { };
}

class Y
{
     virtual int abc() { };
}
class Z : public X,public Y
{
     virutal int abc() { return a };
     int a;
}

Now what I understand is both Y and Z have the reference to Z::abc() in their virtual tables which helps to resolve the correct function to call. Consider

Y *y = new Z;
Z *z = new Z;
y->abc() // I understand this is done by reaching the vptr of y by this = this + sizeof (X)
and z->abc() // z has its own vptr reachable

My understanding is that in both the cases the "this" pointer is passed and after finding out the correct abc() to call, how does the programm reach the int value "a"? enter image description here

How does the compiler calculate the address of " int a" correctly based on type of the object passed?

4

3 回答 3

3

这都是实现细节,不同的编译器做不同的事情。有两种常见的方法来解决这个问题,但都依赖于修复this函数定义中指针所指的内容。

一种方法是让this指针始终指向完整的对象(至少在该虚函数的最终覆盖器级别)。在这种方法中,在存在多重继承的情况下,vtable 中的条目不包含指向实际函数的指针,而是指向调整this指针然后跳转到覆盖器的蹦床的指针。这种方法的优点是,对于最左边的非空基以及在所有单继承情况下,vtable 中的条目实际上是覆盖器,并且没有相关的成本。这是 Itanium C++ ABI 中采用的方法,它用于不同的操作系统,包括 Linux。

另一种方法是始终传递首先声明成员函数的子对象的地址。在这种情况下,调用者在跳过 vtable之前this调整指针以引用子对象。与第一种情况一样,如果没有偏移量(第一个非空基,单继承),编译器不需要添加任何调整并且不会产生任何成本。在最终覆盖器的实现中,编译器使用声明函数的基指针的偏移量,而不是完整对象的偏移量。我相信在 Windows/Visual Studio 中就是这种情况,但不要相信我的话,因为我无权访问 VS C++ ABI 来确认这一点。

第三种方法是直接将调整存储在 vtable 中。这种方法不太常见,并且即使在不需要更新偏移量时也会产生调整偏移量的成本(通过添加 0)。我不知道任何当前使用这种方法的编译器。

于 2013-10-03T02:34:23.667 回答
1

你可以治疗

 virtual int abc() { return a };

作为

 virtual int abc(Z * const this) { return this->a };

所以对于每一个非静态成员函数,都有一个hidden指向对象的指针。所以编译器只要能找到虚方法,就知道在哪里了a

于 2013-10-03T02:23:41.377 回答
0

以 John 的观点为基础,如果派生类覆盖基类方法,编译器将自动创建所谓的指向派生类中的 vtable 的 vpointer。this派生类中幕后的指针指向 vpointer,然后指向派生类的 vtable。这就是多态性的工作原理。

于 2013-10-03T02:33:34.173 回答