前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++基础(七).多态(1)

C++基础(七).多态(1)

作者头像
franket
发布2021-09-15 19:51:44
4950
发布2021-09-15 19:51:44
举报
文章被收录于专栏:技术杂记

前言

C++语言是C语言的拓展,C语言是面向过程的,C++在C的基础上增加了面向对象的方法

什么是面向对象呢,面向对象就是将数据和对数据的加工方法打包在一起,进行模块化的调用,通过方法来进行数据交换的一种设计方法

Tip: 本人关于程序的认知,可以参看前面写的 一个运维人员的编程思维

面向对象的程序设计有四个主要特点:

  • 抽象
  • 封装
  • 继承
  • 多态

下面就通过C++来对面向对象的核心特性进行分享

Tip: 此文中的基础概念参看了 《C++ 虚函数&纯虚函数&抽象类&接口&虚基类》 《C++抽象基类和纯虚函数》


概要


多态

在面向对象语言中,接口的多种不同实现方式即为多态

多态特性中,可以将子类类型的指针赋值给父类类型的指针;可以用父类的指针指向子类的实例(对象),然后通过父类的指针调用实际子类的成员函数

多态是通过虚函数实现的

多态可以让父类的指针有“多种形态”,这是一种泛型技术(所谓泛型技术,就是试图使用不变的代码来实现可变的算法)


虚函数

虚函数是一种特殊的成员函数,它的一般格式如下

代码语言:javascript
复制
class <类名>
    {
        virtual <类型><函数名>(<参数表>);
        …
    };

虚函数必须是类的非静态成员函数(且非构造函数),其访问权限是public

虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数进行重新定义。在派生类中定义的函数应与虚函数具有相同的形参个数和形参类型(覆盖),以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数

虚函数可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时,基类虚成员函数调用基类指针,则会调用其真正指向的对象的成员函数,而不是基类中定义的成员函数(只要派生类改写了该成员函数)。若不是虚函数,则不管基类指针指向哪个派生类对象,调用时都会调用基类中定义的那个函数

Tip: 虚函数的引入就是为了实现多态的特性,让不同的子类可以有不同的实现方式


纯虚函数

纯虚函数是一种特殊的虚函数,它的一般格式如下

代码语言:javascript
复制
class <类名>
    {
        virtual <类型><函数名>(<参数表>)=0;
        …
    };

许多情况下,在基类中不能对虚函数给出有意义的实现,则把它声明为纯虚函数,它的实现留给该基类的派生类去做

纯虚函数的作用是为派生类提供一个一致的接口(纯虚函数相当于接口,不能直接实例化,需要派生类来实现函数定义)


虚函数与纯虚函数的区别

  • 1)类里声明为虚函数的话,这个函数是实现的,哪怕是空实现,它的作用就是为了能让这个函数在它的子类里面可以被重载,这样的话,编译器就可以使用后期绑定来达到多态了,纯虚函数只是一个接口,是个函数的声明而已,它要留到子类里去实现
  • 2)虚函数在子类里面也可以不重载的;但纯虚必须在子类去实现,这就像Java的接口一样。通常我们把很多函数加上virtual,是一个好的习惯,虽然牺牲了一些性能,但是增加了面向对象的多态性,因为你很难预料到父类里面的这个函数不在子类里面不去修改它的实现
  • 3)虚函数的类用于“实作继承”,继承接口的同时也继承了父类的实现。当然我们也可以完成自己的实现。纯虚函数的类用于“接口继承”,主要用于通信协议方面。关注的是接口的统一性,实现由子类完成。一般来说,接口类中只有纯虚函数的
  • 4)带纯虚函数的类叫抽象类,这种基类不能直接生成对象,而只有被继承,并且重写其虚函数后,才能使用

抽象类

带有纯虚函数的类称为抽象类

抽象类是一种特殊的类,它是为了抽象和设计的目的而建立的,它处于继承层次结构的较上层。抽象类是不能定义对象的,在实际中为了强调一个类是抽象类,可将该类的构造函数说明为保护的访问控制权限

抽象类的主要作用是将有关的组织在一个继承层次结构中,由它来为它们提供一个公共的根,相关的子类是从这个根派生出来的

抽象类刻画了一组子类的操作接口的通用语义,这些语义也传给子类。一般而言,抽象类只描述这组子类共同的操作接口,而完整的实现留给子类

抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类没有重新定义纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然还是一个 抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体类了

抽象类中,既可以有抽象方法,也可以有具体方法或者叫非抽象方法。抽象类中,既可以全是抽象方法,也可以全是非抽象方法。一个继承于抽象类的子类,只有实现了父类所有的抽象方法才能够是非抽象类


接口

接口只是一个概念,它在C++中用抽象类来实现

接口是专门被继承的,接口存在的意义也是被继承,和C++里的抽象类里的纯虚函数是相同的,不能被实例化

当继承一个接口时,接口里的所有函数必须全部被覆盖

Tip: 接口的意义在于提前协定标准,构建共识,可以更为高效和低成本地进行大规模协作,利于构建模块化和松耦合的系统


抽象类与接口的区别

  • 抽象类可以有构造方法,接口中不能有构造方法
  • 抽象类中可以有普通成员变量,接口中没有普通成员变量
  • 接口里边全部方法都必须是abstract的,抽象类的可以有实现了的方法
  • 抽象类中的抽象方法的访问类型可以是public,protected,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型
  • 抽象类中可以包含静态方法,接口中不能包含静态方法
  • 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是 public static final 类型,并且默认即为 public static final 类型

虚基类

虚基类是一个相对概念,形式如下

代码语言:javascript
复制
class derive : virtual public base
{
};

虚基类是相对于它的派生类而言的,它本身可以是一个普通的类。只有它的派生类虚继承它的时候,它才称作虚基类,如果没有虚继承的话,就称为基类。比如类B虚继承于类A,那类A就称作类B的虚基类,如果没有虚继承,那类B就只是类A的基类

虚继承主要用于一个类继承多个类的情况,避免重复继承同一个类两次或多次

例如 由类A派生类B和类C,类D又同时继承类B和类C,这时候类D就要用虚继承的方式避免重复继承类A两次


代码示例

要求

  • 写一个程序,定义抽象基类Shape, 由它派生3个子类,Circle(圆),Rectangle(矩形),Trapezoid(梯形)
  • 用虚函数分别计算几种图形的面积,并求他们的和

要求:用基类指针数组,使它的每一个元素指向一个派生类对象

代码语言:javascript
复制
 Shape *p[3]

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 概要
    • 多态
      • 虚函数
        • 纯虚函数
          • 虚函数与纯虚函数的区别
            • 抽象类
              • 接口
                • 抽象类与接口的区别
                  • 虚基类
                    • 代码示例
                      • 要求
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档