c++ 面向对象的三大特性详解—封装、继承、多态
面向对象:对象是指具体的某一个事物,这些事物的抽象就是类,类中包含数据(成员变量)和动作(成员方法)。
面向对象的三大特性:
封装: 将具体的实现过程和数据封装成一个函数,只能通过接口进行访问,降低耦合性。
继承: 子类继承父类的特征和行为,子类有父类的非 private 方法或成员变量,子类可以对父类的方法进行重写,增强了类之间的耦合性,但是当父类中的成员变量、成员函数或者类本身被 final 关键字修饰时,修饰的类不能继承,修饰的成员不能重写或修改。
多态: 多态就是不同继承类的对象,对同一消息做出不同的响应,基类的指针指向或绑定到派生类的对象,使得基类指针呈现不同的表现方式。
封装可以使得代码模块化,继承可以扩展已经存在的代码,目的都是为了代码重用。多态的目的是为了接口重用。
1、继承
一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名,形式如下:
1 | class child: public parent |
其中public
可以替换为protect
、private
类型决定了子类将会把基类的内容继承为什么类型。
1.1 继承类型
我们几乎不使用 protected 或 private 继承,通常使用 public 继承。当使用不同类型的继承时,遵循以下几个规则:
公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。
1.2访问权限总结:
因此,如果基类成员不想被派生类的成员函数访问,应该在基类中声明为private。
一个派生类继承了所有的基类方法,但下列情况除外:
基类的构造函数、析构函数和拷贝构造函数。
基类的重载运算符。
基类的友元函数。
1.3多继承
多继承即一个子类可以有多个父类,它继承了多个父类的特性。
C++ 类可以从多个类继承成员,语法如下:
1 | class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,… |
2、多态
C++多态(polymorphism)是通过虚函数来实现的.
当类存在多层的层次结构,并且类之间是通过继承关联的时,C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
📌简单来说就是一个基类被派生为多个子类,子类中对基类中的函数进行了重写。我们希望利用子类的指针或者引用可以实现调用重写的函数,而不是基类中原本的函数,这时候,我们需要对基类中和子类中同名的函数前加上关键字
virtual
。这里我们应该称为是函数的重写。
虚函数是类方法中的一种特殊函数,当你调用它时,它会匹配派生最远的重写版本。这种特性是多态性。匹配的规则是相同的函数签名(函数名,参数个数与类型)以及返回类型(返回类型可以不相同,但必须存在派生关系)。虚函数仅需要再前面加上一个virtual
关键字即可.
论是基类版本还是派生类版本,我们都在函数前面使用了virtual
关键字,事实上,派生类中的virtual
关键字并不是必要的。一旦基类中的方法打上了virtual
标签,那么派生类中匹配的函数也是虚函数。但是,还是建议在后面的派生类中加上virtual
关键字,作为虚函数的一种提醒,以便后面可能还会有更远的派生。
到底什么时候使用虚函数?大部分时候,我们希望派生类是真正的“重写”基类函数,而不是“隐藏”。所以一般建议将所有方法都声明为virtual
。既然如此,为什么编译器不默认这样做呢,其实对于Java语言来说,所有的方法默认是虚函数。但是使用虚函数是有代价的,相对于普通函数,虚函数的调用代价稍高,但是这种差别不会太大,所以还是建议所有方法都使用virtual
关键字
析构函数要声明为虚函数
对于析构函数,大部分时间我们只需要使用编译器提供的默认版本就好,除非涉及到释放动态分配的内存。但是如果存在继承,虚函数最好声明为虚函数。否则删除一个实际指向派生类的基类指针,只会调用基类的析构函数,而不会调用派生类的析构函数以及派生类数据成员的析构函数。 这样就可能造成内存泄露。
参考文献: