0%

C++对象模型 Data Semantics

1
2
3
4
5
6
7
8
class Point3d {
public:
// ...
protected:
float x, y, z;
};

&&Point3d::x; // 获得x在class object中的offset

两种访问方式,在x属于一个virtual base class的member的时候有差异,否则都是编译期就确定的(一次访问)

1
2
origin.x = 0.0;
pt->x = 0.0;

继承与Data member

  • 只要继承:多个继承,可能会有多个padding,造成浪费

  • 加上多态

    • 增加vptr
    • 增加vtbl
    • 构造函数中设定vptr初始值
    • 析构函数中删除vptr
  • 多重继承:多重继承下,转换指针,将基地址加上中间的base class object大小

  • 虚继承:两种方式,第二种使用正值负值在vtable中索引virtual subobject的偏移量,减少空间

指向Data member的指针

1
&Point3d::z;

得到z坐标在class object中的offset

DataMember指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <_types/_uint64_t.h>
#include <iostream>
#include <memory>

class Point {};

class Point1d : public Point {
public:
int x;
Point1d(int x_) : x(x_) {}
};

class Point2d : public Point1d {
public:
int y;
Point2d(int x_, int y_) : Point1d(x_), y(y_) {}
};

int main() {
printf("&Point2d::x: %p\n", &Point2d::x); // 0x0
printf("&Point2d::y: %p\n", &Point2d::y); // 0x4
Point2d p(1, 2);
printf("&p: %p\n", &p); // 0x16f50ed68
printf("&p.x: %p\n", &p.x); // 0x16f50ed68
printf("&p.y: %p\n", &p.y); // 0x16f50ed6c
printf("&p.y - &p.x: %lu\n", (uint64_t)(&p.y) - (uint64_t)(&p.x)); // 4
}

虚继承:
看起来在clang上是有个单独的vbtable,而不是在vtable的前边

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <_types/_uint32_t.h>
#include <iostream>

struct B {
int x;
B(int x_) : x(x_){};
B() = default;
};

struct D1 : virtual B {
uint32_t y1;
D1(int x_, int y1_) : B(x_), y1(y1_){};
D1() = default;
};

struct D2 : virtual B {
uint32_t y2;
D2(int x_, int y2_) : B(x_), y2(y2_){};
D2() = default;
};

struct D : D1, D2 {
D(int x, int y1, int y2) : B(x), D1(x, y2), D2(x, y2) {}
};

int main() {
D d(1, 2, 3);
/*
------
D1(16byte): vptr, y1
------
D2(12byte): vptr, y1
------
B(4byte): x
------
*/
printf("&d=%p\n", &d); // let it be x
printf("&d.y1=%p\n", &d.y1); // x+8 (vbtable for d1 at x)
printf("&d.y2=%p\n", &d.y2); // x+24 (vbtable for d2 at x+16)
printf("&d.x=%p\n", &d.x); // x+28

int *vtable_d1 = (int *)*(int **)&d; // d1 vtable
int *vtable_d2 = (int *)(*(int **)&d + 16); // d2 vtable

printf("%d\n", vtable_d1[0]); // offset from D1end to B (12)
printf("%d\n", vtable_d2[0]); // offset from D2end to B (0)
}