C++的三大特性封装继承和多态

Posted liangyc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++的三大特性封装继承和多态相关的知识,希望对你有一定的参考价值。

 

封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用

  • 封装:封装是在设计类的一个基本原理,是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与对数据进行的操作进行有机的结合,形成“类”,其中数据和函数都是类的成员。

  • 继承:如果一个类别B“继承自”另一个类别A,就把这个B称为“A的子类”,而把A称为“B的父类别”也可以称“A是B的超类”。继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。

    1. 访问权限

      • public: 父类对象内部、父类对象外部、子类对象内部、子类对象外部都可以访问。
      • protected:父类对象内部、子类对象内部可以访问,父类对象外部、子类对象外部都不可访问。
      • private:父类对象内部可以访问,其他都不可以访问。

      |访问对象|public|protected|private|
      |-|-|-|-|
      |父类|可见|可见|可见|
      |子类|可见|可见|不可见|
      |父类外部|可见|不可见|不可见|
      |子类外部|可见|不可见|不可见|

    2. 继承方式
      ps.三种继承方式不影响子类对父类的访问权限,子类对父类只看父类的访问控制权。继承方式是为了控制子类(也称派生类)的调用方(也叫用户)对父类(也称基类)的访问权限。public、protected、private三种继承方式,相当于把父类的public访问权限在子类中变成了对应的权限。 如protected继承,把父类中的public成员在本类中变成了protected的访问控制权限;private继承,把父类的public成员和protected成员在本类中变成了private访问控制权。

      ps.友元是类级别的,不存在继承的问题。

  • 多态:多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。多态(polymorphism),字面意思多种形状。

    1. 静态多态:静态多态也称为静态绑定或早绑定。编译器在编译期间完成的,编译器根据函数实参的类型(可能会进行隐式类型转换),可推断出要调用那个函数,如果有对应的函数就调用该函数,否则出现编译错误。

      • 函数重载

        编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定)。

      • 泛型编程

        泛型编程就是指编写独立于特定类型的代码,泛型在C++中的主要实现为模板函数和模板类。
        泛型的特性:

          1. 函数模板并不是真正的函数,它只是C++编译生成具体函数的一个模子。
          1. 函数模板本身并不生成函数,实际生成的函数是替换函数模板的那个函数,比如上例中的add(sum1,sum2),这种替换是编译期就绑定的。
          3. 函数模板不是只编译一份满足多重需要,而是为每一种替换它的函数编译一份。
          4. 函数模板不允许自动类型转换。
          5. 函数模板不可以设置默认模板实参。比如template <typename T=0>不可以。
        
    2. 动态多态
      c++的动态多态是基于虚函数的。对于相关的对象类型,确定它们之间的一个共同功能集,然后在基类中,把这些共同的功能声明为多个公共的虚函数接口。各个子类重写这些虚函数,以完成具体的功能。客户端的代码(操作函数)通过指向基类的引用或指针来操作这些对象,对虚函数的调用会自动绑定到实际提供的子类对象上去。

    3. 宏多态(?)
      带变量的宏可以实现一种初级形式的静态多态:

      #include <iostream>
      #include <string>
      
      // 定义泛化记号:宏ADD
      #define ADD(A, B) (A) + (B);
      
      int main()
      
          int i1(1), i2(2);
          std::string s1("Hello, "), s2("world!");
          int i = ADD(i1, i2);                        // 两个整数相加
          std::string s = ADD(s1, s2);                // 两个字符串“相加”
          std::cout << "i = " << i << "/n";
          std::cout << "s = " << s << "/n";
      
      
    4. 动态多态和静态多态的比较

      1. 静态多态
        • 优点:
          1. 由于静多态是在编译期完成的,因此效率较高,编译器也可以进行优化;
          2. 有很强的适配性和松耦合性,比如可以通过偏特化、全特化来处理特殊类型;
          3. 最重要一点是静态多态通过模板编程为C++带来了泛型设计的概念,比如强大的STL库。
        • 缺点:
          1. 由于是模板来实现静态多态,因此模板的不足也就是静多态的劣势,比如调试困难、编译耗时、代码膨胀、编译器支持的兼容性不能够处理异质对象集合
      2. 动态多态
        • 优点:
          1. OO设计,对是客观世界的直觉认识;
          2. 实现与接口分离,可复用
          3. 处理同一继承体系下异质对象集合的强大威力
        • 缺点:
          1. 运行期绑定,导致一定程度的运行时开销;
          2. 编译器无法对虚函数进行优化
          3. 笨重的类继承体系,对接口的修改影响整个类层次;
      3. 不同点:
        • 本质不同,早晚绑定。静态多态在编译期决定,由模板具现完成,而动态多态在运行期决定,由继承、虚函数实现;
        • 动态多态中接口是显式的,以函数签名为中心,多态通过虚函数在运行期实现,静态多台中接口是隐式的,以有效表达式为中心,多态通过模板具现在编译期完成
      4. 相同点:
        • 都能够实现多态性,静态多态/编译期多态、动态多态/运行期多态;
        • 都能够使接口和实现相分离,一个是模板定义接口,类型参数定义实现,一个是基类虚函数定义接口,继承类负责实现;

 

以上是关于C++的三大特性封装继承和多态的主要内容,如果未能解决你的问题,请参考以下文章

面向对象编程三大特性-封装、继承、多态

三大特性:封装,继承,多态

面向对象三大特性(封装/继承/多态)

[C++] 面向对象语言的三大特性--继承

[C++] 面向对象语言的三大特性--继承

12:面向对象三大特性(封装继承多态)之继承