本文主要以示例说明C++对象成员函数的存储布局,有关理论知识,请参考Fuction语意学。
一、成员函数
1.1、无继承
#include <iostream>
using namespace std;
class X
{
public:
int a = 0;
int b = 1;
virtual void f1() { cout << "X::f1()" << endl; }
virtual void f2() { cout << "X::f2()" << endl; }
virtual void f3() { cout << "X::f3()" << endl; }
};
int main()
{
X x;
cout << "X:" << endl;
cout << "sizeof(X) = " << sizeof(X) << endl;
cout << "vptr address: " << (&x) << endl;
cout << "x.a address: " << &x.a << endl;
cout << "x.b address: " << &x.b << endl;
using f = void (*)();
f fun = reinterpret_cast<f>(*(int*)(&x));
f t1 = reinterpret_cast<f>(((int*)fun)[0]);
f t2 = reinterpret_cast<f>(((int*)fun)[1]);
f t3 = reinterpret_cast<f>(((int*)fun)[2]);
t1();
t2();
t3();
return 0;
}
运行时的内存结果如下:
程序运行结果如下:
x的内存布局如下所示:
1.2、单一继承
#include <iostream>
using namespace std;
class X
{
public:
int a = 0;
int b = 1;
virtual void f1() { cout << "X::f1()" << endl; }
virtual void f2() { cout << "X::f2()" << endl; }
virtual void f3() { cout << "X::f3()" << endl; }
};
class Y : public X
{
};
class Z : public X
{
void f1() { cout << "Z::f1()" << endl; }
void f2() { cout << "Z::f2()" << endl; }
};
int main()
{
X x;
cout << "X:" << endl;
cout << "sizeof(X) = " << sizeof(X) << endl;
cout << "vptr address: " << (&x) << endl;
cout << "x.a address: " << &x.a << endl;
cout << "x.b address: " << &x.b << endl;
Y y;
cout << "Y:" << endl;
cout << "sizeof(Y) = " << sizeof(Y) << endl;
cout << "vptr address: " << (&y) << endl;
cout << "y.a address: " << &y.a << endl;
cout << "y.b address: " << &y.b << endl;
Z z;
cout << "Z:" << endl;
cout << "sizeof(Z) = " << sizeof(Z) << endl;
cout << "vptr address: " << (&z) << endl;
cout << "z.a address: " << &z.a << endl;
cout << "z.b address: " << &z.b << endl;
using f = void (*)();
f funx = reinterpret_cast<f>(*(int*)(&x));
f x1 = reinterpret_cast<f>(((int*)funx)[0]);
f x2 = reinterpret_cast<f>(((int*)funx)[1]);
f x3 = reinterpret_cast<f>(((int*)funx)[2]);
x1();
x2();
x3();
f funy = reinterpret_cast<f>(*(int*)(&y));
f y1 = reinterpret_cast<f>(((int*)funy)[0]);
f y2 = reinterpret_cast<f>(((int*)funy)[1]);
f y3 = reinterpret_cast<f>(((int*)funy)[2]);
y1();
y2();
y3();
f funz = reinterpret_cast<f>(*(int*)(&z));
f z1 = reinterpret_cast<f>(((int*)funz)[0]);
f z2 = reinterpret_cast<f>(((int*)funz)[1]);
f z3 = reinterpret_cast<f>(((int*)funz)[2]);
z1();
z2();
z3();
return 0;
}
其中,Y没有覆盖X的虚函数,因此Y的对象中虚函数的地址与X中虚函数的地址相同,都指向X中的虚函数;Z中覆盖了f1()、f2(),没有覆盖f3(),因此,Z的对象中f1()和f2()的地址与X中的f1()和f2()的地址不相同,分别指向X和Z中的虚函数;而f3()的地址相同,都指向X中的虚函数。
运行时的内存结果如下:
程序运行结果如下:
x、y、z的内存布局如下:
1.3、多重继承
#include <iostream>
using namespace std;
class X
{
public:
int a = 0;
int b = 1;
virtual void fx1() { cout << "X::fx1()" << endl; }
virtual void fx2() { cout << "X::fx2()" << endl; }
};
class Y
{
public:
virtual void fy1() { cout << "Y::fy1()" << endl; }
virtual void fy2() { cout << "Y::fy2()" << endl; }
};
class M : public X, public Y
{
void fx1() { cout << "M::fx1()" << endl; }
void fy1() { cout << "M::fy1()" << endl; }
};
int main()
{
X x;
cout << "X:" << endl;
cout << "sizeof(X) = " << sizeof(X) << endl;
cout << "vptr address: " << (&x) << endl;
cout << "x.a address: " << &x.a << endl;
cout << "x.b address: " << &x.b << endl;
Y y;
cout << "Y:" << endl;
cout << "sizeof(Y) = " << sizeof(Y) << endl;
cout << "vptr address: " << (&y) << endl;
M m;
cout << "M:" << endl;
cout << "sizeof(M) = " << sizeof(M) << endl;
cout << "vptr address: " << (&m) << endl;
cout << "m.a address: " << &m.a << endl;
cout << "m.b address: " << &m.b << endl;
using f = void (*)();
f funx = reinterpret_cast<f>(*(int*)(&x));
f x1 = reinterpret_cast<f>(((int*)funx)[0]);
f x2 = reinterpret_cast<f>(((int*)funx)[1]);
x1();
x2();
f funy = reinterpret_cast<f>(*(int*)(&y));
f y1 = reinterpret_cast<f>(((int*)funy)[0]);
f y2 = reinterpret_cast<f>(((int*)funy)[1]);
y1();
y2();
f funmx = reinterpret_cast<f>(*(int*)(&m));
f mx1 = reinterpret_cast<f>(((int*)funmx)[0]);
f mx2 = reinterpret_cast<f>(((int*)funmx)[1]);
mx1();
mx2();
f funmy = reinterpret_cast<f>(((int*)(&m))[3]);
f my1 = reinterpret_cast<f>(((int*)funmy)[0]);
f my2 = reinterpret_cast<f>(((int*)funmy)[1]);
my1();
my2();
return 0;
}
其中,M没有覆盖X中的fx2(),因此M中虚函数fx2()的地址与X中虚函数fx2()的地址相同,都指向X中的虚函数fx2();M覆盖了X中的fx1(),因此M中虚函数fx1()的地址与X中虚函数fx1()的地址不相同,分别指向X和M中的虚函数。M和Y的关系与之类似。
运行时的内存结果如下:
程序运行结果如下:
x、y、m的内存布局如下:
1.4、虚继承
1.4.1、单一虚继承
#include <iostream>
using namespace std;
class X
{
public:
int a = 0;
int b = 1;
virtual void fx1() { cout << "X::fx1()" << endl; }
};
class Y :virtual public X
{
public:
virtual void fy1() { cout << "Y::fy1()" << endl; }
};
class Z :virtual public X
{
public:
virtual void fz1() { cout << "Z::fz1()" << endl; }
void fx1() { cout << "Z::fx1()" << endl; }
};
int main()
{
X x;
cout << "X:" << endl;
cout << "sizeof(X) = " << sizeof(X) << endl;
cout << "vptr address: " << (&x) << endl;
cout << "x.a address: " << &x.a << endl;
cout << "x.b address: " << &x.b << endl;
Y y;
cout << "Y:" << endl;
cout << "sizeof(Y) = " << sizeof(Y) << endl;
cout << "vptr address: " << (&y) << endl;
cout << "y.a address: " << &y.a << endl;
cout << "y.b address: " << &y.b << endl;
Z z;
cout << "Z:" << endl;
cout << "sizeof(Z) = " << sizeof(Z) << endl;
cout << "vptr address: " << (&z) << endl;
cout << "z.a address: " << &z.a << endl;
cout << "z.b address: " << &z.b << endl;
using f = void (*)();
f funx = reinterpret_cast<f>(*(int*)(&x));
f x1 = reinterpret_cast<f>(((int*)funx)[0]);
x1();
f funy = reinterpret_cast<f>(*(int*)(&y));
f y1 = reinterpret_cast<f>(((int*)funy)[0]);
y1();
f funyx = reinterpret_cast<f>(*((int*)(&y) + 2));
f yx1 = reinterpret_cast<f>(((int*)funyx)[0]);
yx1();
f funz = reinterpret_cast<f>(*(int*)(&z));
f z1 = reinterpret_cast<f>(((int*)funz)[0]);
z1();
f funzx = reinterpret_cast<f>(*((int*)(&z) + 2));
f zx1 = reinterpret_cast<f>(((int*)funzx)[0]);
zx1();
return 0;
}
其中,Y通过虚继承的方式继承于X,在Y的对象中,首先存放的是Y的虚函数地址,接下来存放的是虚基类表指针,然后是Y的数据成员,最后是X的子对象。在虚基类表中存放的是偏移值,第一个是虚基类表指针距离子对象Y的偏移,第二个是距离虚基类子对象X的偏移。在Y中没有覆盖X的虚函数,因此Y中虚函数fx1()的地址与X中虚函数fx1()的地址相同,都指向X中的虚函数fx1();Z覆盖了X中的fx1(),因此Z中虚函数fx1()的地址与X中虚函数fx1()的地址不相同,分别指向Z和X中的虚函数fx1()。
运行时的内存结果如下:
程序运行结果如下:
x、y、z的内存布局如下:
1.4.2、多重虚继承
#include <iostream>
using namespace std;
class X
{
public:
int a = 0;
int b = 1;
virtual void fx1() { cout << "X::fx1()" << endl; }
};
class Y :virtual public X
{
public:
int c = 2;
virtual void fy1() { cout << "Y::fy1()" << endl; }
};
class Z :virtual public X
{
public:
virtual void fz1() { cout << "Z::fz1()" << endl; }
};
class M :public Y, public Z
{
public:
int d = 3;
virtual void fm1() { cout << "M::fm1()" << endl; }
void fx1() { cout << "M::fx1()" << endl; }
};
int main()
{
X x;
cout << "X:" << endl;
cout << "sizeof(X) = " << sizeof(X) << endl;
cout << "vptr address: " << (&x) << endl;
cout << "x.a address: " << &x.a << endl;
cout << "x.b address: " << &x.b << endl;
Y y;
cout << "Y:" << endl;
cout << "sizeof(Y) = " << sizeof(Y) << endl;
cout << "vptr address: " << (&y) << endl;
cout << "y.a address: " << &y.a << endl;
cout << "y.b address: " << &y.b << endl;
cout << "y.c address: " << &y.c << endl;
Z z;
cout << "Z:" << endl;
cout << "sizeof(Z) = " << sizeof(Z) << endl;
cout << "vptr address: " << (&z) << endl;
cout << "z.a address: " << &z.a << endl;
cout << "z.b address: " << &z.b << endl;
M m;
cout << "M:" << endl;
cout << "sizeof(M) = " << sizeof(M) << endl;
cout << "vptr address: " << (&m) << endl;
cout << "m.a address: " << &m.a << endl;
cout << "m.b address: " << &m.b << endl;
cout << "m.c address: " << &m.c << endl;
cout << "m.d address: " << &m.d << endl;
using f = void (*)();
f funx = reinterpret_cast<f>(*(int*)(&x));
f x1 = reinterpret_cast<f>(((int*)funx)[0]);
x1();
f funy = reinterpret_cast<f>(*(int*)(&y));
f y1 = reinterpret_cast<f>(((int*)funy)[0]);
y1();
f funyx = reinterpret_cast<f>(*((int*)(&y) + 3));
f yx1 = reinterpret_cast<f>(((int*)funyx)[0]);
yx1();
f funz = reinterpret_cast<f>(*(int*)(&z));
f z1 = reinterpret_cast<f>(((int*)funz)[0]);
z1();
f funzx = reinterpret_cast<f>(*((int*)(&z) + 2));
f zx1 = reinterpret_cast<f>(((int*)funzx)[0]);
zx1();
f funm = reinterpret_cast<f>(*(int*)(&m));
f m1 = reinterpret_cast<f>(((int*)funm)[0]);
m1();
f funmy = reinterpret_cast<f>(*((int*)(&m)));
f my1 = reinterpret_cast<f>(((int*)funmy)[0]);
my1();
f funmz = reinterpret_cast<f>(*((int*)(&m) + 3));
f mz1 = reinterpret_cast<f>(((int*)funmz)[0]);
mz1();
f funmx = reinterpret_cast<f>(*((int*)(&m) + 6));
f mx1 = reinterpret_cast<f>(((int*)funmx)[0]);
mx1();
return 0;
}
在M的对象中,首先存放的是Y的子对象,需要注意的是:M中的虚函数地址存放在Y的子对象的虚函数表中,接下来是Z的子对象,然后是M的数据成员,最后是X的子对象。
运行时的内存结果如下:
程序运行结果如下:
x、y、z、m的内存布局如下: