C++之多态

06-02 582阅读

开始新的征程啦———多态,它也是C++的三大特性之一。

C++之多态

文章目录

  • 一、多态的概念
  • 二、多态的定义和实现
    • 2.1多态的定义
    • 2.2 实现动态多态所需要的条件(2个)
    • 2.3 虚函数的定义
    • 2.4 虚函数的重写/覆盖
    • 2.5 虚函数重写中的问题
      • 2.5.1 协变
      • 2.5.2 析构函数的重写
      • 2.6 override和final关键字
      • 2.6 重载/重写/隐藏
      • 三、纯虚函数和抽象类
      • 四、多态的原理
        • 4.1 虚函数表指针
        • 4.2 父子类的虚函数表指针的区分
        • 4.3 多态的原理
        • 4.4 动态绑定与静态绑定
        • 4.4 虚函数表

          一、多态的概念

          通俗来讲的话,就是多种形态。多态性(Polymorphism) 指的是 “同一接口,不同实现” 的能力。

          多态分为编译时多态(静态多态)和运行时多态(动态多态),什么属于静态多态呢?像之前学习的函数重载以及模板(函数模板+类模板)就属于静态多态,为什么叫编译时多态?因为实参传给形参的匹配是在编译时完成的(传不同的参数就可以调用不用的函数,通过参数的不同达到多种形态);什么是运行时多态呢?即:去完成某个行为(函数),传不同的对象,来完成不同的行为,就会达到多种形态。(多态举例:去同一个买票的窗口,普通人去是全价,但是学生是半价,不用的对象,不同的行为)

          我们这节讲述的都是动态的多态。

          二、多态的定义和实现

          2.1多态的定义

          动态多态是指在运行时根据对象的实际类型来决定调用哪个函数,与【指针 / 引用的静态类型】无关,不是由这个决定的。它通过虚函数(Virtual Functions) 和继承机制实现,核心是 运行时类型识别 和 虚函数表(VTABLE) 的动态调度。

          简单理解就是:一个继承关系下的类类型的对象,去调用同一函数,产生了不同的行为。

          2.2 实现动态多态所需要的条件(2个)

          非常重要,这个是前提条件

          1. 被调用的函数必须是虚函数

            1.2想让函数有多种形态,首先需要让基类中的那个成员函数成为虚函数

          2. 必须是基类(父类)指针 / 引用去调用虚函数

            【注意注意:

            (1)基类基类基类,派生类是没法调用虚函数的哈。而且父类的指针/引用,既可以指向父类对象,又可以指向子类对象(ptr是person(父)类类型的指针,不管你传什么样的派生类过来,他在这里都会进行切割,因此ptr它始终都指向父类的那一部分);

            (2)指针或引用,如果是person p;是调用不了的哈,它只是一个单纯的对象,不是指针也不是引用】

          为什么必须是基类的指针/引用呢?因为只有基类的指针或引用才能既指向派生类对象,又能指向基类对象。

          2.3 虚函数的定义

          上述所需的第一个条件是虚函数。那什么是虚函数呢?

          在 C++ 中,虚函数是实现动态多态的核心机制。它允许通过 [基类的指针或引用] 调用 [派生类的特定函数] ,而具体调用哪个函数在 运行时 根据对象的实际类型确定,而非编译时.

          虚函数的定义:虚函数是在基类中用 virtual 关键字声明的(成员函数),派生类可以 重写(Override) 该函数以提供自己的实现。【非成员函数不能加virtual来修饰,也就是说这个函数是在类里面的】

          virtual这个关键字加在成员函数的返回值的前面

          class person
          {
          public:
          	virtual void Buy()
          	{
          		cout 
          public:
          	virtual void func(int val = 0)  //A中的val时0,B中的是1
          	{
          		std::cout 
          public:
          	void func(int val = 1)
          	{
          		std::cout    //先在堆上创建一个 B 类的对象实例,然后将地址赋给A类指针。再用A类指针(基类指针)调用虚函数
              //new B                          赋值给A* p
          	A* p = new B; //在堆上分配的内存大小为sizeof(B),包含(子类)B自身的成员和从A继承的成员
          	p-func();   //p是基类。条件之一:用基类的指针去调用虚函数
          	//输出结果是class B-0
          	return 0;
          }
          
          	std::cout 
          public:
          	virtual void BuyTicket()
          	{
          		cout 
          	virtual void BuyTicket()
          	{
          		cout 
          	person* p1 = new person;  
          	p1-BuyTicket();//买票——全折;
          	person& p2 = *p1;  //引用
          	p2.BuyTicket();//买票——全折;
          	person* s1 = new student;  //这里会发生切割关系
          	s1-BuyTicket();//买票——半折;这里调用的是派生类中的BuyTicket函数。
          	person& s2 = *s1;
          	s2.BuyTicket();//买票——半折;这里调用的其实也是派生类中的BuyTicket函数。
          	return 0;
          }
          
          public:
          	virtual ~A()
          	{
          		cout 
          public:
          	virtual ~B()
          	{
          		cout 
          	A* a1 = new A;
          	A* a2 = new B;
          	delete a1;
          	delete a2;
          	return 0;
          }
          
          public:
          	virtual void print() final { }//表明print这个虚函数不能构成重写操作
          };
          
          public:
          	virtual void drive() = 0; //drive成为了纯虚函数
              //所以car类成为了抽象类
          };
          class xiaomi:public car
          {
          	//没有对纯虚函数进行重写,所以xiaomi类也是抽象类
          };
          class xinjie :public car
          {
          public:
          	virtual void drive()
          	{
          		cout 
          	car* a1 = new car;
          	car* a2 = new xiaomi;
          	car* a3 = new xinjie;
          	return 0;
          }
          
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码