C++ 对象模型
struct Base {
Base() = default;
~Base() = default;
void Func() {}
int a;
int b;
};
int main() {
Base a;
return 0;
}

struct Base {
Base() = default;
virtual ~Base() = default;
void FuncA() {}
virtual void FuncB() {
printf("FuncB\n");
}
int a;
int b;
};
int main() {
Base a;
return 0;
}
这个含有虚函数的结构体大小为16,在对象的头部,前8个字节是虚函数表的指针,指向虚函数的相应函数指针地址,a占4个字节,b占4个字节,总大小为16。

offset_to_top(0):表示当前这个虚函数表地址距离对象顶部地址的偏移量,因为对象的头部就是虚函数表的指针,所以偏移量为0。
RTTI指针:指向存储运行时类型信息(type_info)的地址,用于运行时类型识别,用于typeid和dynamic_cast。
struct Base {
Base() = default;
virtual ~Base() = default;
void FuncA() {}
virtual void FuncB() {
printf("Base FuncB\n");
}
int a;
int b;
};
struct Derive : public Base{
public:
int c;
};
int main() {
Base a;
Derive d;
return 0;
}

这里的FuncB函数,还是Base类中的FuncB,因为在子类中没有重写这个函数,那么如果子类重写这个函数后对象布局是什么样的,请继续往下看。
4. 单继承下含有覆盖函数的类对象是什么布局?
struct Base {
Base() = default;
virtual ~Base() = default;
void FuncA() {}
virtual void FuncB() {
printf("Base FuncB\n");
}
int a;
int b;
};
struct Derive : public Base{
void FuncB() override {
printf("Derive FuncB \n");
}
int c;
};
int main() {
Base a;
Derive d;
return 0;
}

,表示Base和Derive的虚表地址是相同
struct BaseA {
BaseA() = default;
virtual ~BaseA() = default;
void FuncA() {}
virtual void FuncB() {
printf("BaseA FuncB\n");
}
int a;
int b;
};
struct BaseB {
BaseB() = default;
virtual ~BaseB() = default;
void FuncA() {}
virtual void FuncC() {
printf("BaseB FuncC\n");
}
int c;
int d;
};
struct Derive : public BaseA, public BaseB{
};
int main() {
BaseA a;
Derive d;
return 0;
}

:表示当前这个虚函数表(BaseA,Derive)地址距离对象顶部地址的偏移量,因为对象的头部就是虚函数表的指针,所以偏移量为0。
RTTI中有了两项,表示BaseA和Derive的虚表地址是相同的,BaseA类里的虚函数和Derive类里的虚函数都在这个链条下,截至到offset_to_top(-16)之前都是BaseA和Derive的虚函数表。
offset_to_top(-16):表示当前这个虚函数表(BaseB)地址距离对象顶部地址的偏移量,因为对象的头部就是虚函数表的指针,所以偏移量为-16,这里用于this指针偏移,下一小节会介绍。
struct BaseA {
BaseA() = default;
virtual ~BaseA() = default;
void FuncA() {}
virtual void FuncB() {
printf("BaseA FuncB\n");
}
int a;
int b;
};
struct BaseB {
BaseB() = default;
virtual ~BaseB() = default;
void FuncA() {}
virtual void FuncC() {
printf("BaseB FuncC\n");
}
int c;
int d;
};
struct Derive : public BaseA, public BaseB{
void FuncB() override {
printf("Derive FuncB \n");
}
void FuncC() override {
printf("Derive FuncC \n");
}
};
int main() {
BaseA a;
Derive d;
return 0;
}

7. 多继承中不同的继承顺序产生的类对象布局相同吗?
struct BaseA {
BaseA() = default;
virtual ~BaseA() = default;
void FuncA() {}
virtual void FuncB() {
printf("BaseA FuncB\n");
}
int a;
int b;
};
struct BaseB {
BaseB() = default;
virtual ~BaseB() = default;
void FuncA() {}
virtual void FuncC() {
printf("BaseB FuncC\n");
}
int c;
int d;
};
struct Derive : public BaseB, public BaseA{
void FuncB() override {
printf("Derive FuncB \n");
}
void FuncC() override {
printf("Derive FuncC \n");
}
};
int main() {
BaseA a;
Derive d;
return 0;
}

BaseB的虚函数表指针和数据在上面,BaseA的虚函数表指针和数据在下面,以A,B的顺序继承,对象的布局就是A在上B在下,以B,A的顺序继承,对象的布局就是B在上A在下。

浙公网安备 33010602011771号