一、前言
前面文章中分析了对象内存布局,对象大小已经不难理解了,这里集中总结一下。
个人笔记,不保证严谨和正确☺,如有错误还望指出!
二、实例代码
2.1 代码
运行环境 64位,G++ 4.6.4版本
#include<iostream>
#include<string>
using namespace std;
class A {}; // 1
class B // 16
{
public:
int bv;
virtual void f() { cout << "B::f()" << endl; }
B(): bv(1) {}
};
class C // 16
{
public:
int cv;
virtual void h() { cout << "C::h()" << endl; }
C(): cv(2) {}
};
class D : public B //16
{
public:
int dv;
virtual void f() { cout << "D::f()" << endl; }
D(): dv(3) {}
};
class E : public B //16
{
public:
int ev;
virtual void f() { cout << "E::f()" << endl; }
E(): ev(4) {}
};
class F : public B, public C // 32
{
public:
int fv;
virtual void g() { cout << "F::g()" << endl; }
F(): fv(5) {}
};
class G : public D, public E // 40
{
public:
int gv;
virtual void g() { cout << "G::g()" << endl; }
G(): gv(6) {}
};
class H : virtual public B // 32
{
public:
int hv;
virtual void g() { cout << "H::g()" << endl; }
H(): hv(7) {}
};
class I : virtual public B // 32
{
public:
int iv;
virtual void g() { cout << "I::g()" << endl; }
I(): iv(8) {}
};
class J : public H, public I // 48
{
public:
int jv;
virtual void jf() { cout << "J::jf()" << endl; }
J(): jv(9) {}
};
class K : virtual public B, virtual public C // 48
{
public:
int kv;
virtual void g() { cout << "K::g()" << endl; }
K(): kv(10) {}
};
// 测试
void test()
{
cout << "szieof(A): " << sizeof(A) << endl;
cout << "szieof(B): " << sizeof(B) << endl;
cout << "szieof(C): " << sizeof(C) << endl;
cout << "szieof(D): " << sizeof(D) << endl;
cout << "szieof(E): " << sizeof(E) << endl;
cout << "szieof(F): " << sizeof(F) << endl;
cout << "szieof(G): " << sizeof(G) << endl;
cout << "szieof(H): " << sizeof(H) << endl;
cout << "szieof(I): " << sizeof(I) << endl;
cout << "szieof(J): " << sizeof(J) << endl;
cout << "szieof(K): " << sizeof(K) << endl;
}
// 测试 J
void testJ()
{
J b;
cout << ">>>>>>sizeof(J): " << sizeof(J) << endl;
typedef void(*ptrType)(void);
ptrType pFun = NULL;
ptrType** pVtab = (ptrType**)&b;
ptrType* pHead = (ptrType*)(&b); // pHead: 指向的是对象空间首地址(即,虚函数表地址)
ptrType* pVptr = (ptrType*)(*pHead); // pVptr: 虚函数表第一个函数地址
int index = 0; // 对象内存访问下标
auto fun = [&](string strName, string strFunName, int maxj)
{
ptrType* pVptr = (ptrType*)(*pHead);
cout << "[" << index << "] " << strName <<"::vptr->" << endl;
for (int j = 0; j < maxj; ++j)
{
pFun = (ptrType)*(pVptr+j);
cout << " [" << j <<"] ";
pFun();
}
pHead = pHead + 1;
++index;
cout << "[" << index << "] " << strFunName << " = " << (int)*((int *)pHead) << endl;
};
fun("H", "H::hv", 2);
pHead = pHead + 1; ++index;
fun("I", "I::iv", 1);
pHead = (ptrType*)((int *)pHead + 1);
cout << "[" << index << "] I::hv = " << (int)*((int *)pHead) << endl;
pHead = (ptrType*)((int *)pHead + 1); ++index;
fun("B", "B::bv", 1);
pHead = pHead + 1; ++index;
}
// 测试 K
void testK()
{
K b;
cout << ">>>>>>sizeof(K): " << sizeof(K) << endl;
typedef void(*ptrType)(void);
ptrType pFun = NULL;
ptrType** pVtab = (ptrType**)&b;
ptrType* pHead = (ptrType*)(&b); // pHead: 指向的是对象空间首地址(即,虚函数表地址)
ptrType* pVptr = (ptrType*)(*pHead); // pVptr: 虚函数表第一个函数地址
int index = 0; // 对象内存访问下标
auto fun = [&](string strName, string strFunName, int maxj)
{
pVptr = (ptrType*)(*pHead); // pVptr: 虚函数表第一个函数地址
cout << "[" << index << "] " << strName <<"::vptr->" << endl;
for (int j = 0; j < maxj; ++j)
{
pFun = (ptrType)*(pVptr+j);
cout << " [" << j <<"] ";
pFun();
}
pHead = pHead + 1;
++index;
cout << "[" << index << "] " << strFunName << " = " << (int)*((int *)pHead) << endl;
pHead = pHead + 1; ++index;
};
fun("K", "K::kv", 1);
fun("B", "B::bv", 1);
fun("C", "C::cv", 1);
}
int main()
{
test();
testJ();
testK();
return 0;
}
2.2 执行结果
2.3 分析
A:空类需要有一个地址标记。大小为 1。
B:一个虚表指针(8),和一个 int(B::bv) 需要内存对齐(8)。大小为 16 = 8 + 8。
C:同B。大小为 16。
D:一个虚函数表指针(8),虚函数表记录的是(D::f()),B类中一个int(B::bv)对象,D类中一个int(D::dv)对象。大小为 16 = 8 + 4 + 4。
E:同D。大小为16。
F:一个虚函数指针(8),虚函数表记录的是(B::f(), F::g()),B类中一个 int(B::bv) 需要内存对齐(8), 一个虚函数指针(8),虚函数表记录的是(C::h()),C类中一个 int(C::cv)(4),F类中一个 int(F::fv)(4)。大小为 32 = 8 + 8 + 8 + 4 + 4。
G:一个虚函数指针(8),虚函数表记录的是(D::f(), G::g()),B类中一个 int(B::bv)(4),D类中一个 int(D::dv)(4),一个虚函数指针(8),虚函数表记录的是(E::f()),B类中一个 int(B::bv)(4),类中一个 int(E::dv)(4),G类中一个 int(G::gv) 需要内存对齐(8)。大小为 40 = 8 + 4 + 4 + 8 + 4 + 4 + 8。
H:一个虚函数指针(8),虚函数表记录的是(H::g()),H类中一个 int(H::hv) 需要内存对齐(8),一个虚函数指针(8),虚函数表记录的是(B::f()),B类中一个 int(B::bv) 需要内存对齐(8)。大小为 32 = 8 + 8 + 8 + 8。
I:同H。大小为 32。
J:一个虚函数指针(8),虚函数表记录的是(H::g(), J::jf()),H类中一个 int(H::hv) 需要内存对齐(8),一个虚函数指针(8),虚函数表记录的是(I::g()),I类中一个 int(I::iv)(4),J类中一个 int(J::jv)(4), 一个虚函数指针(8),虚函数表记录的是(B::f()),B类中一个 int(B::bv) 需要内存对齐(8)。大小为 48 = 8 + 8 + 8 + 4 + 4 + 8 + 8。
K:一个虚函数指针(8),虚函数表记录的是(K::g()),K类中一个 int(K::kv) 需要内存对齐(8),一个虚函数指针(8),虚函数表记录的是(B::f()),B类中一个 int(B::bv) 需要内存对齐(8),一个虚函数指针(8),虚函数表记录的是(C::h()),C类中一个 int(C::cv) 需要内存对齐(8)。大小为 48 = 8 + 8 + 8 + 8 + 8 + 8。
J 内存布局和虚函数表
K 内存布局和虚函数表