C++面向对象(01) — 封装、继承、多态

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++语言提供了虚继承的机制:

1
2
3
4
class A {};
class B : virtual public A {};   // 虚继承
class C : virtual public A {};   // 虚继承
class D : public B, public C {}; // A类型的成员在D类型中只会保留一份。

3. 多态

多态就是“多种形态”,同一个接口可以有多种表现。C++中多态可以分为两类: 编译时多态运行时多态
编译时多态: 函数重载、模板属于编译时多态,应为编译器在编译时就可以确定调用哪个函数。
运行时多态: 虚函数和继承属于运行时多态,函数调用在运行时根据对象的实际类型动态决定,这是通过虚函数表实现的。

comments powered by Disqus