1 class 与 struct
-
class
是一种特殊的struct
- 在内存中,
class
依旧可以看作变量的集合 class
与struct
遵循相同的内存对齐规则class
中的成员函数(是函数,只可能存放在代码段中)与成员变量(是数据,存放于三个数据区中:栈,堆,全局数据区)是分开存放的- 每个对象有独立的成员变量
- 所有对象共享类中的成员函数
- 在内存中,
-
问题:
sizeof(A)
= ?,sizeof(B)
= ?sizeof(A) = 20
sizeof(B) = 20
class A { int i; int j; char c; double d; }; struct B { int i; int j; char c; double d; };
-
示例1:对象内存布局
-
Demo
#include <iostream> #include <string> using namespace std; class A { int i; int j; char c; double d; public: void print() { cout << "i = " << i << ", " << "j = " << j << ", " << "c = " << c << ", " << "d = " << d << endl; } }; struct B { int i; int j; char c; double d; }; int main() { A a; cout << "sizeof(A) = " << sizeof(A) << endl; // 20 bytes cout << "sizeof(a) = " << sizeof(a) << endl; // 20 bytes cout << "sizeof(B) = " << sizeof(B) << endl; // 20 bytes a.print(); //强制类型转换:重新解释这段内存 B* p = reinterpret_cast<B*>(&a); p->i = 1; p->j = 2; p->c = 'c'; p->d = 3; a.print(); p->i = 100; p->j = 200; p->c = 'C'; p->d = 3.14; a.print(); return 0; }
-
编译运行
sizeof(A) = 20 sizeof(a) = 20 sizeof(B) = 20 i = 134515232, j = -1075608584, c = ?, d = 4.85991e-270 i = 1, j = 2, c = c, d = 3 i = 100, j = 200, c = C, d = 3.14
-
2 C++ 对象模型分析
-
运行时的对象退化为结构体的形式
- 所有成员变量在内存中依次分布
- 成员变量间可能存在内存空隙
- 可以通过内存地址直接访问成员变量
- 访问权限关键字在运行时失效
-
类的对象调用成员函数原理
- 类的成员函数位于代码段中
- 调用成员函数时对象地址作为参数隐式传递
- 成员函数通过对象地址访问成员变量
- C++ 语法规则隐藏了对象地址的传递过程
-
示例2:对象本质分析
-
Demo1:C++ 类对象调用成员函数
#include <iostream> #include <string> using namespace std; class Demo { int mi; int mj; public: Demo(int i, int j) { mi = i; mj = j; } int getI() { return mi; } int getJ() { return mj; } int add(int value) { return mi + mj + value; } }; int main() { Demo d(1, 2); cout << "sizeof(d) = " << sizeof(d) << endl; //8 cout << "d.getI() = " << d.getI() << endl; cout << "d.getJ() = " << d.getJ() << endl; cout << "d.add(3) = " << d.add(3) << endl; return 0; }
-
Demo2:C 语言实现上述过程
//test.c #include <stdio.h> #include "object.h" int main() { Demo* d = Demo_Create(1, 2); // Demo* d = new Demo(1, 2); printf("d.mi = %d ", Demo_GetI(d)); // d->getI(); printf("d.mj = %d ", Demo_GetJ(d)); // d->getJ(); printf("Add(3) = %d ", Demo_Add(d, 3)); // d->add(3); // d->mi = 100; //error Demo_Free(d); return 0; } //object.h #ifndef _OBJECT_H_ #define _OBJECT_H_ typedef void Demo; Demo* Demo_Create(int i, int j); int Demo_GetI(Demo* pThis); int Demo_GetJ(Demo* pThis); int Demo_Add(Demo* pThis, int value); void Demo_Free(Demo* pThis); #endif //object.c #include "object.h" #include "malloc.h" struct ClassDemo { int mi; int mj; }; Demo* Demo_Create(int i, int j) { struct ClassDemo* ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo)); if( ret != NULL ) { ret->mi = i; ret->mj = j; } return ret; } int Demo_GetI(Demo* pThis) { struct ClassDemo* obj = (struct ClassDemo*)pThis; return obj->mi; } int Demo_GetJ(Demo* pThis) { struct ClassDemo* obj = (struct ClassDemo*)pThis; return obj->mj; } int Demo_Add(Demo* pThis, int value) { struct ClassDemo* obj = (struct ClassDemo*)pThis; return obj->mi + obj->mj + value; } void Demo_Free(Demo* pThis) { free(pThis); }
-
编译运行
d.mi = 1 d.mi = 2 Add(3) = 6
-
3 继承对象模型
-
在 C++ 编译器的内部,类可以理解为结构体
-
子类是由父类成员叠加子类新成员得到的
class Derived : public Demo { int mk; }
-
示例3:继承对象模型
-
Demo
#include <iostream> #include <string> using namespace std; class Demo { protected: int mi; int mj; public: void print() { cout << "mi = " << mi << ", " << "mj = " << mj << endl; } }; class Derived : public Demo { int mk; public: Derived(int i, int j, int k) { mi = i; mj = j; mk = k; } void print() { cout << "mi = " << mi << ", " << "mj = " << mj << ", " << "mk = " << mk << endl; } }; struct Test { int mi; int mj; int mk; }; int main() { cout << "sizeof(Demo) = " << sizeof(Demo) << endl; cout << "sizeof(Derived) = " << sizeof(Derived) << endl; Derived d(1, 2, 3); Test* p = reinterpret_cast<Test*>(&d); cout << "Before changing ..." << endl; d.print(); p->mi = 10; p->mj = 20; p->mk = 30; cout << "After changing ..." << endl; d.print(); return 0; }
-
-
编译运行:说明结构体
Test
和类Derived
的内存分布相同sizeof(Demo) = 8 sizeof(Derived) = 12 Before changing ... mi = 1, mj = 2, mk = 3 After changing ... mi = 10, mj = 20, mk = 30
4 多态对象模型
-
多态的概念:相同的行为方式,不同的行为结果。由具体的编程语言实现,在 C++ 中由虚函数实现
-
C++ 多态的实现原理
- 当类中声明虚函数时,编译器会在类中生成一个虚函数表(VTABLE)
- 虚函数表是一个存储成员(虚)函数地址的数据结构
- 虚函数表是由编译器自动生成维护的
virtual
成员函数会被编译器放入虚函数表中- 存在虚函数时,每个对象中都有一个指向虚函数表的指针:虚函数表指针(VPTR)
-
示例4:多态对象模型
-
Demo
#include <iostream> #include <string> using namespace std; class Demo { protected: int mi; int mj; public: virtual void print() { cout << "mi = " << mi << ", " << "mj = " << mj << endl; } }; class Derived : public Demo { int mk; public: Derived(int i, int j, int k) { mi = i; mj = j; mk = k; } void print() { cout << "mi = " << mi << ", " << "mj = " << mj << ", " << "mk = " << mk << endl; } }; struct Test { void* p; //模拟虚函数表指针,放在最开始的四个字节处 int mi; int mj; int mk; }; int main() { cout << "sizeof(Demo) = " << sizeof(Demo) << endl; cout << "sizeof(Derived) = " << sizeof(Derived) << endl; Derived d(1, 2, 3); Test* p = reinterpret_cast<Test*>(&d); cout << "Before changing ..." << endl; d.print(); p->mi = 10; p->mj = 20; p->mk = 30; cout << "After changing ..." << endl; d.print(); return 0; }
-
编译运行
sizeof(Demo) = 12 sizeof(Derived) = 16 Before changing ... mi = 1, mj = 2, mk = 3 After changing ... mi = 10, mj = 20, mk = 30
-
-
示例:多态本质分析
-
Demo
//test.c #include "stdio.h" #include "51-2.h" void run(Demo* p, int v) { int r = Demo_Add(p, v); printf("r = %d ", r); } int main() { Demo* pb = Demo_Create(1, 2); Derived* pd = Derived_Create(1, 22, 333); printf("pb->add(3) = %d ", Demo_Add(pb, 3)); printf("pd->add(3) = %d ", Derived_Add(pd, 3)); run(pb, 3); run(pd, 3); Demo_Free(pb); Demo_Free(pd); return 0; } // #ifndef _51_2_H_ #define _51_2_H_ typedef void Demo; typedef void Derived; Demo* Demo_Create(int i, int j); int Demo_GetI(Demo* pThis); int Demo_GetJ(Demo* pThis); int Demo_Add(Demo* pThis, int value); void Demo_Free(Demo* pThis); Derived* Derived_Create(int i, int j, int k); int Derived_GetK(Derived* pThis); int Derived_Add(Derived* pThis, int value); #endif // #include "51-2.h" #include "malloc.h" static int Demo_Virtual_Add(Demo* pThis, int value); static int Derived_Virtual_Add(Demo* pThis, int value); struct VTable // 2. 定义虚函数表数据结构 { int (*pAdd)(void*, int); // 3. 虚函数表里面存储什么??? }; struct ClassDemo { struct VTable* vptr; // 1. 定义虚函数表指针 ==》 虚函数表指针类型??? int mi; int mj; }; struct ClassDerived { struct ClassDemo d; int mk; }; static struct VTable g_Demo_vtbl = { Demo_Virtual_Add }; static struct VTable g_Derived_vtbl = { Derived_Virtual_Add }; Demo* Demo_Create(int i, int j) { struct ClassDemo* ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo)); if( ret != NULL ) { ret->vptr = &g_Demo_vtbl; // 4. 关联对象和虚函数表 ret->mi = i; ret->mj = j; } return ret; } int Demo_GetI(Demo* pThis) { struct ClassDemo* obj = (struct ClassDemo*)pThis; return obj->mi; } int Demo_GetJ(Demo* pThis) { struct ClassDemo* obj = (struct ClassDemo*)pThis; return obj->mj; } // 6. 定义虚函数表中指针所指向的具体函数 static int Demo_Virtual_Add(Demo* pThis, int value) { struct ClassDemo* obj = (struct ClassDemo*)pThis; return obj->mi + obj->mj + value; } // 5. 分析具体的虚函数!!!! int Demo_Add(Demo* pThis, int value) { struct ClassDemo* obj = (struct ClassDemo*)pThis; return obj->vptr->pAdd(pThis, value); } void Demo_Free(Demo* pThis) { free(pThis); } Derived* Derived_Create(int i, int j, int k) { struct ClassDerived* ret = (struct ClassDerived*)malloc(sizeof(struct ClassDerived)); if( ret != NULL ) { ret->d.vptr = &g_Derived_vtbl; ret->d.mi = i; ret->d.mj = j; ret->mk = k; } return ret; } int Derived_GetK(Derived* pThis) { struct ClassDerived* obj = (struct ClassDerived*)pThis; return obj->mk; } static int Derived_Virtual_Add(Demo* pThis, int value) { struct ClassDerived* obj = (struct ClassDerived*)pThis; return obj->mk + value; } int Derived_Add(Derived* pThis, int value) { struct ClassDerived* obj = (struct ClassDerived*)pThis; return obj->d.vptr->pAdd(pThis, value); }
-
编译运行
-