1 物件模型的前世

  類在c++編譯器內部可以理解成結構體,所以在物件模型分析時,我們可以把 class  當作一種特殊的 struct;

  1)在記憶體中 class 可以看作是普通成員變數的集合;

  2)class 與 struct 遵循相同的記憶體對齊規則;

  3)class 中的 成員變數 與 成員函式 是分開存放的;

    1. 每個物件都有獨立的成員變數;成員變數可以儲存在 棧空間、堆空間、全域性資料區;

    2. 所有物件共享類的成員函式;成員函式 只能儲存在 程式碼段;

      理解下面這 3 句話:(物件地址 == this指標)

        1、成員函式通過物件地址訪問成員變數;

        2、呼叫成員函式時將物件地址作為引數隱式傳遞;

        3、c++語法規則隱藏了物件地址的傳遞過程;

  4)訪問許可權關鍵字在執行時失效;(外界訪問類的私有成員時只在編譯階段有效)

  注:若沒有明確說是 static 成員時,預設都是 普通成員;    

  程式碼分析:

 1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 #pragma pack(push, 4) // 將資料儲存方式設定為 壓棧方式,位元組對齊方式 設定為 4
7
8 class A
9 {
10 static int count; // 靜態成員變數在類的外部單獨分配空間,靜態成員變數在程式內部位於 全域性資料區
11 char *pt; // 8 bytes(OS:64bit)
12 char c; // 1 bytes
13 int i; // 4 bytes
14 double d; // 8 bytes
15 public:
16 A(const char *pt = NULL, char c = ' ', int i = 0, double d = 0)
17 {
18 this->pt = new char(' ');
19 this->c = ' ';
20 this->i = i;
21 this->d = 0;
22 }
23 void print()
24 {
25 cout << "*pt = " << *pt << ", "
26 << "c = " << c << ", "
27 << "i = " << i << ", "
28 << "d = " << d << endl;
29 }
30 ~A()
31 {
32 delete pt;
33 }
34 };
35
36 int A:: count = 0;
37
38 struct B
39 {
40 char *pt; // 8 bytes(OS:64bit)
41 char c; // 1 bytes
42 int i; // 4 bytes
43 double d; // 8 bytes
44 };
45
46 #pragma pack(pop)// 恢復壓棧前的設定
47
48 int main()
49 {
50 A a;
51
52 cout << "sizeof(a) = " << sizeof(a) << endl; // 24 bytes
53 cout << "sizeof(A) = " << sizeof(A) << endl; // 24 bytes
54 cout << "sizeof(B) = " << sizeof(B) << endl; // 24 bytes
55
56 a.print(); // *pt = , i = 0, c = , d = 0
57
58 B* p = reinterpret_cast<B*>(&a); // struct 與 class 的記憶體模型相同
59
60 *(p->pt) = 'P';
61 p->c = 'C';
62 p->i = 100;
63 p->d = 3.14;
64
65 a.print(); // *pt = P, i = 100, c = C, d = 3.14
66
67 return 0;
68 }

單個類物件的記憶體模型練習

 1 // demo.h
2
3 #ifndef _DEMO_H_
4 #define _DEMO_H_
5
6 typedef void Demo;
7
8 Demo* demo_Create(int i, int j); // 等價於 c++ 建構函式 Demo(int i, int j)
9 int demo_getI(Demo *pThis); // 等價於 c++ 成員函式 int getI()
10 int demo_getJ(Demo *pThis); // 等價於 c++ 成員函式 int getJ()
11 int demo_add(Demo *pThis, int value); // 等價於 c++ 成員函式 int add(int value)
12 Demo demo_free(Demo *pThis); // 等價於 c++ 解構函式 ~Demo()
13
14 #endif
15
16 // demo.c
17 #include "demo.h"
18 #include "malloc.h"
19
20 typedef struct DemoStruct
21 {
22 int i;
23 int j;
24 } DemoStruct;
25
26 Demo* demo_Create(int i, int j)
27 {
28 DemoStruct *this = (DemoStruct*)malloc( sizeof(DemoStruct) );
29
30 if(this != NULL)
31 {
32 this->i = i;
33 this->j = j;
34 }
35
36 return this;
37 }
38
39 int demo_getI(Demo *pThis)
40 {
41 DemoStruct *this = (DemoStruct*)pThis;
42
43 return this->i;
44 }
45
46 int demo_getJ(Demo *pThis)
47 {
48 DemoStruct *this = (DemoStruct*)pThis;
49
50 return this->j;
51 }
52
53 int demo_add(Demo *pThis, int value)
54 {
55 DemoStruct *this = (DemoStruct*)pThis;
56
57 return (this->i + this->j + value);
58 }
59
60 Demo demo_free(Demo *pThis)
61 {
62 DemoStruct *this = (DemoStruct*)pThis;
63
64 free(this);
65 }
66
67 // mian.c
68
69 #include "stdio.h"
70 #include "demo.h"
71
72 int main(int argc, char const *argv[])
73 {
74 Demo *d = demo_Create(10, 20); // 相當於 c++中的 Demo* d = new Demo(10, 20);
75
76 int i = demo_getI(d); // 相當於 c++中的 d->getI();
77 int j = demo_getJ(d); // 相當於 c++中的 d->getJ();
78 int v = demo_add(d, 30); // 相當於 c++中的 d->add(30);
79
80 printf("i = %d, j = %d, v = %d\n", i, j, v); // i = 10, j = 20, v = 60
81
82 // d->i = 11; // err, 相當於 c++的private屬性
83
84 demo_free(d);
85
86 return 0;
87 }

用c語言復現c++中的this指標

補充:位元組對齊知識點

 1 /*
2 #pragma pack(push, 4) 《=》
3 #pragma pack(push)
4 #pragma pack(4)
5 */
6 #pragma pack(push, 4) // 將資料儲存方式設定為 壓棧方式,位元組對齊方式 設定為 4
7 struct S
8 {
9 char c;
10 int i;
11 };
12 #pragma pack(pop) // 恢復壓棧前的設定
13
14 #pragma pack (4) //作用:C編譯器將按照4個位元組對齊。
15 struct S
16 {
17 char c;
18 int i;
19 }
20 #pragma pack () // 作用:取消自定義位元組對齊方式

c/c++位元組對齊方式設定

2 繼承中的物件模型

  子類是由父類成員疊加子類中的新成員形成的。