zoukankan      html  css  js  c++  java
  • 多态

    封装、继承、多态是C++的三大利器。

    多态性是设计模式的基础:

    需求:根据实际对象类型来判断重写函数的调用。
    父类指针 指向父类对象 调用父类中定义的函数;
    父类指针 指向子类对象 调用子类中定义的重写函数。

    多态:同样的调用语句多种不同的表现形态

    实现方式:基类中 函数 声明为 virtual。子类中重写该函数。

    多态的实用性:
    用基类指针传参 写一个函数,后来人新写的功能可以通过把对象传给基类指针,该函数就具有调用后来新加功能的效果

    C语言 间接赋值 是指针存在的最大意义
    1、一个形参,一个实参
    2、实参地址赋给形参
    3、形参取*间接改变实参的值

    C++ 面向对象3大概念
    封装:突破C函数的概念 用类做函数参数的时候,可以使用对象的属性 和对象的方法
    继承: 代码复用
    多态:可以使用未来,利用基类指针接受子类地址,调用子类的重写函数(该函数在基类中是virtual)

    实现多态的三个条件
    1、继承
    2、同名虚函数重写
    3、父类指针 指向 子类对象

    静态联编:重载函数不加virtual关键字,就根据指针类型去执行
    动态联编:加virtual关键字,运行时候根据具体类型执行不同对象的函数,变现成多态
    动态联编:if和switch

    虚析构函数:

    构造函数不能为虚函数,析构函数可以为虚函数,用于指引delete运算符正确析构动态对象。
    void delete(A *base)
    {
      delete base;
    }
    希望将A的子类C的对象C* c1赋给base后,可以释放c1,执行C的析构函数,但此时只会释放基类; 
    而继承中构造函数的调用规则是:
    定义C的对象,会自动依次调用A,B,C的构造函数,执行delete(A* base)后只释放了一次基类内存,就会发生内存泄漏。

    我们希望:
    通过父类指针 把所有的子类对象的析构函数都执行一遍;
    通过父类指针 释放所有的子类资源
    只需要将基类的析构函数 定义为虚函数即可,C继承自B,B继承自A,只需要要将父类的析构函数定义为虚函数即可,A和B都需要
    此时通过delete(A* base)就可以逆序调用析构函数了(不然,程序猿手动逐个析构就不给力了)

    重载,重写,重定义
    重载:在同一个类中进行。
    重写:在父类和子类的不同类中,有两种
    加virtual的是多态
    不加virtual的是重定义


    重要:子类不能重载父类的函数(重载只能发生在一个类中)
    所以,当子类中没有父类的同名函数时,子类可以调用父类的函数,
    当子类有父类的同名函数(参数(个数或类型)不同),C++认为子类同名函数会覆盖父类的函数,想要调用父类同名函数,需要加域作用符。

    不然,C++编译器以为你要调用子类的该函数重载,可没有找到,就报错。

    虚函数:
    有虚函数时,对象第一个成员是vptr指针,该指针指向虚函数表,虚函数表存放虚成员函数指针

    证明vptr指针存在,sizeof(对象);同一个类一个有虚函数一个没有虚函数,建立对象测试即可。


    vptr的分步初始化,先将父类的虚函数表赋给vptr,后将子类虚函数表赋给vptr。所以父类构造函数调用虚函数不会发生多态。

    父类指针步长与子类指针步长不一致,是在子类新加入成员变量造成的。
    指针的大小取决于指向的对象:

    class A
    {
    public: 
        int a;
    public:
        virtual void print()
        {
            cout << "asd" << endl;
        }
    }
    
    class B : class A
    {
    public: 
        int b; //造成子类的指针与父类指针大小不一致
    public:
        virtual void print()
        {
          cout << "asd" << endl;
        }
    }    

    sizeof(A) //8字节 a 和 隐含的vptr指针(有虚函数时,就存在一个vptr指针的成员变量)

    sizeof(B) //12字节 a , b , vptr.

    如何实现多态(重要)
    1、C++编译器为每个类定义对象时,提前布局的vptr指针
    2、通过vptr指针访问虚函数表
    3、当有虚函数的调用时,找到虚函数的入口地址来进行动态的值绑定

    多态的原理:
    1、效果:同样调用语句有多种不同的表现形态(一个函数在父类和不同子类穿梭时有不同的形态)
    2、成立的三个条件:继承、virtual函数重写,父类指针指向子类对象
    3、多态的C++实现:virtual关键字告诉编译器这个函数要支持多态;
    不是根据指针类型判断如何调用;而是通过指针所指向的实际对象类型来判断如何调用。
    4、多态的理论基础:
    动态联编 静态联编。根据实际的对象类型来判断重写函数的调用。
    5、多态的重要意义:设计模式的基础
    6、实现多态的基础手段:函数指针做函数参数


    多态原理探究:
    理论知识:
    1、当类中声明虚函数是,编译器会在类中生成一个虚函数表
    2、虚函数表是一个存储类成员函数指针的数据结构
    3、虚函数表是由编译器自动生成与维护的
    4、virtual成员函数会被编译器放入虚函数表中
    5、当存在虚函数时,每个对象中都有一个指向虚函数表的指针vptr
    c++编译器给父类对象、子类对象提前布局vptr指针;当进行howToPrint(Parent* base)函数时,
    C++编译器不需要区分子类对象或者父类对象,只需要在base指针中,找vptr指针即可
    vptr一般作为类对象的第一个成员。


    注:当类中有多个虚函数时,编译器只给类布局一个vptr指针,计算类的大小时注意。

  • 相关阅读:
    命名空间 和 class_exist() 问题
    浏览器中打开文件
    memcach 安装
    MySQL事务机制
    Xcode10更新报错:library not found for -lstdc++.6.0.9
    appium-chromedriver@3.0.1 npm ERR! code ELIFECYCLE npm ERR! errno 1
    npm audit fix
    使用WebStorm/IDEA上传本地项目到GitHub
    vue-cli(vue脚手架)超详细教程
    [Swift 开发] 使用闭包传值(typealias)
  • 原文地址:https://www.cnblogs.com/Lunais/p/5697010.html
Copyright © 2011-2022 走看看