基于对象程序设计
基于对象即对应了面向对象三大特征中的“封装”,可以简单概括为:
将一组关联的数据和一组对应的操作绑定在一起
优点:
- 模块化,将系统分解为若干个对象的交互,降低了问题的复杂度
- 将接口与实现分离,实现了具体实现的灵活性
设计目标:
- 可读性:
- 内存安全
设计过程:
- 设计类的成员变量
-
选择合适的数据类型 和 可读性好的变量名
-
为成员变量设置合适的访问权限
-
还需要考虑以下两点:
- 成员变量是否只读——>是否添加const修饰符
- 成员变量是否需要共享——>是否添加static修饰符
- 设计类的构造函数
-
使用成员初始化列表
-
类的成员变量是否存在指针
- 若存在,考虑是否存在浅拷贝问题,如果存在,考虑禁止或者实现拷贝构造函数和赋值运算符重载函数
- 设计类的析构函数
- 无指针类型或者无系统资源(文件描述符等)通常使用默认的析构函数
- 若类成员变量存在指针,需要释放指针指向的内存,同时将指针值置空,避免野指针。
- 设计类的成员方法
-
先实现相应的成员方法
-
再考虑是否需要实现自定义的运算符重载函数
-
考虑是否要给成员方法添加修饰符:
- 只读方法 const
- 方法不依赖对象,静态方法 static
- 方法比较简单, 内联方法 inline
- 考虑是否需要添加友元类,友元函数
面向对象程序设计
面向对象设计的主要目标是为了实现多态,实现代码的动态绑定,提高可维护性。
多态:
静态(编译时期)的多态:函数重载,函数名和返回值相同,参数列表不同
动态(运行时期)的多态:基类指正指向派生类对象,通过该指针调用同名覆盖方法,通过动态绑定来实现
多态的目的:
- 实现开闭原则,添加新功能不需要修改源代码,只用实现一个新类
- 隔离变化点,将模块划分为稳定的framework和不稳定的hook,通过多态将它们隔离开
多态实现:
一个类定义了虚函数,编译阶段编译器为该类产生一个唯一的vftable虚函数表,虚函数表
存储了RTTI指针和虚函数的信息,当程序运行时,每张虚函数表会加载到内存中的.rodata区
虚函数表
一个类中定义了虚函数,类的对象在运行时,内存开始部分,多存储一个vfptr虚函数指针,
指向相应类型的虚函数表vftable
虚函数的数量,不影响对象内存大小(vfptr),影响的是虚函数表的大小
如果派生类中,与基类中的虚函数,返回值,函数名,参数列表都相同,自动处理为虚函数
动态绑定的汇编:
mov eax, dword ptr[pb]
mov ecx, dword ptr[eax]
call ecx
设计步骤:
- 基类
-
考虑成员变量
- 需要被派生类继承,将访问权限设置为protected
- 只是内部使用的,设置为private
-
考虑多态接口的设计
- 将接口设置为virtual,如果该类不需要实例化,可设置为纯虚函数
- 考虑是否需要将析构函数设置为虚析构函数,如果派生类中会有指针指向堆上动态分配的内存,为了能动态绑定派生类的析构函数,则需要将基类的析构函数设置为虚函数
- 派生类
-
考虑继承方式
-是否存在多重继承,以及可能由于多重继承而出现菱形继承的问题,如果存在,需要使用虚继承
-
重写虚函数的方法,来实现多态
- 注意只能通过由指针/引用调用虚函数来实现动态绑定