考虑下面的代码行
#include<iostream>
using namespace std;
class base
{
int i;
public:
void printb()
{
cout << "This pointer of base "<<this<<endl;
}
};
class derived: public base
{
int i;
public:
void printd()
{
cout << "This pointer of derived "<<this<<endl;
}
};
main()
{
derived d1;
d1.printd();
d1.printb();
}
在64位ubuntu机器上用g ++(4.8.4)编译后得到的结果是
This pointer of derived 0x7ffe74697ac0
This pointer of base 0x7ffe74697ac0
根据我的理解,base和derived这个指针都是相同的,因为我们用单个对象调用。我将virtual关键字添加到派生类的printd()函数中,如下所示
#include<iostream>
using namespace std;
class base
{
int i;
public:
void printb()
{
cout << "This pointer of base "<<this<<endl;
}
};
class derived: public base
{
int i;
public:
virtual void printd()
{
cout << "This pointer of derived "<<this<<endl;
}
};
main()
{
derived d1;
d1.printd();
d1.printb();
}
上述代码的输出如下
This pointer of derived 0x7ffee969b1d0
This pointer of base 0x7ffee969b1d8
这里的指针值在derived和base中是不同的,即使用单个对象调用。每次运行程序时,派生此指针和基于此指针之间存在1byte的差异。任何人都可以告诉为什么这个指针的差异以及虚拟关键字如何影响这个指针。
通过添加virtual
关键字,您使derived
多态。运行时多态性的常见实现是添加指向对象开头的指针。此vptr指向动态调度的函数表(通常称为vtable)。
因此,base
子对象(不是多态的)通过隐藏指针在derived
超级对象内部偏移。
您会看到指针自动调整,因为编译器会在调用成员函数时注入代码以执行此调整。这样可以确保printb
能够在正确的位置访问base
的所有(潜在)成员。