1. 封装
所谓 “封装” 就是将数据(属性)和操作数据的方法(行为)绑定在一起,并通过访问控制机制对外隐藏实现细节,我们将操作和数据封装到一个类型里面,同时约束类成员的访问权限,在C++里面有三个级别的访问权限。
| 控制符 | 权限 |
|---|---|
| private | 默认权限,仅限类的内部访问 |
| protected | 仅限类的内部访问,和private的区别在于继承时 |
| public | 允许类的外部访问,也就是通过类的实例访问 |
另外还有mutable关键字,这个是用来修饰非静态成员变量的,用于突破const限制的关键字,现在有一个const类型对象(包括const成员函数),正常情况下我们是没有写权限的,但如果它有一个mutable的成员,那么这个mutable修饰的成员是可写的。
2. 继承
2.1. 继承时的权限
继承就是认爹,并继承他爹的特性。和封装类似,继承也有3种权限(public、private、protected),继承权限决定了基类的那些可以被派生类继承,以及继承后这些成员在派生类中的访问权限。
| 基类成员的权限 | 继承权限 | 派生类中的访问权限 |
|---|---|---|
| private | 任意继承方式 | 不可访问 |
| protected | 继承方式 | protected |
| public | private | private |
| public | protected | protected |
| public | public | public |
如果使用struct的话,默认的继承方式就是public的,但是比较少用。
2.2. 单继承、多继承、虚继承
单继承就是只有一个爹,多继承就是有多个爹,多继承更加强大,但可能会引发冲突,我们从是否为菱形继承的角度分为两种情况讨论。
非菱形继承
当多个基类中存在同名成员(方法或变量)时,派生类在访问这些成员时会出现二义性问题。例如,两个基类都定义了 display() 方法,派生类调用 display() 时编译器无法确定应调用哪个基类的实现。此时可以在派生类中重新定义同名方法,覆盖基类的实现。
菱形继承
除了上面的问题,菱形还要面对另一个问题,当两个基类继承自同一个公共祖先时,派生类会包含多个该祖先的副本,导致数据冗余和访问歧义(如果祖先类型有成员)。C++语言提供了虚继承的机制:
|
|
3. 多态
多态就是“多种形态”,同一个接口可以有多种表现。C++中多态可以分为两类: 编译时多态、运行时多态。
编译时多态: 函数重载、模板属于编译时多态,应为编译器在编译时就可以确定调用哪个函数。
运行时多态: 虚函数和继承属于运行时多态,函数调用在运行时根据对象的实际类型动态决定,这是通过虚函数表实现的。