zoukankan      html  css  js  c++  java
  • C++回顾day03---<多态>

    一:错误理解下的多态

    #include <iostream>
    
    using namespace std;
    
    class Parent
    {
    public:
        Parent()
        {
            cout << "Parent construct" << endl;
        }
    
        void overrideFunc()
        {
            cout << "Parent override func" << endl;
        }
    };
    
    class Child:public Parent  //1.有继承
    {
    public:
        Child()
        {
            cout << "Child construct" << endl;
        }
    
        void overrideFunc()  //2.有函数重写
        {
            cout << "Child override func" << endl;
        }
    };
    
    
    void main()
    {
        Parent* p = new Child();  //3.父类指针指向子类对象
        p->overrideFunc();      //4.进行多态调用
        system("pause");
    }

    这里是根据指针类型来判断调用那个函数执行(这是不对的)--->虽然也叫作多态

    二:错误讨论 :使用函数来讨论到底出错在哪里?

    (一)再次回顾对象的产生(重点)(对于一个含有无参构造方法的类的对象的生成)

    class Test
    {
    public:
        Test()
        {
            cout << "Test()" << endl;
        }
    
        Test(int a)
        {
            cout << "Test(int a)" << endl;
        }
    
        void getInfo()
        {
            cout << "use getinfo" << endl;
        }
    };
    
    void main()
    {
        Test t;    //会调用无参构造函数产生一个对象,若是不存在无参构造函数,则这里编译报错
        Test t2(5);    //会调用有参构造函数进行产生对象
        
        t.getInfo();
        t2.getInfo();
    
        system("pause");
    }

    重点:Test t3();是错误的!!!--->虽然声明不会报错,使用的时候会出错

    原因://warning C4930: “Test t3(void)”: 未调用原型函数(是否是有意用变量定义的?)
    会认为该语句表示声明一个名为a的函数,返回类型是Test。

    (二)详细错误案例指出《重点了解》

    class Parent
    {
    public:
        Parent()
        {
            cout << "Parent construct" << endl;
        }
    
        void overrideFunc()
        {
            cout << "Parent override func" << endl;
        }
    };
    
    class Child01:public Parent
    {
    public:
        Child01()
        {
            cout << "Child01 construct" << endl;
        }
    
        void overrideFunc()
        {
            cout << "Child01 override func" << endl;
        }
    };
    
    class Child02 :public Parent
    {
    public:
        Child02()
        {
            cout << "Child02 construct" << endl;
        }
    
        void overrideFunc()
        {
            cout << "Child02 override func" << endl;
        }
    };
    
    void testMulStatus(Parent* p)    //想通过一个父类指针实现对子类对象方法的动态调用
    {
        p->overrideFunc();    //想实现对象方法的动态调用
    }
    
    void main()
    {
        Child01 c1;
        Child02 c2;
        testMulStatus(&c1);
        testMulStatus(&c2);
    
        system("pause");
    }
    本意是通过同一个父类指针,实现对不同的子类的方法的调用

    三:真正的多态实现《重点》

     (一)多态原则

    1.要有继承
    2.要有virtual函数重写
    3.要有父类指针指向子类对象

    (二)代码测试

    class Parent
    {
    public:
        Parent()
        {
            cout << "Parent construct" << endl;
        }
    
        virtual void overrideFunc()
        {
            cout << "Parent override func" << endl;
        }
    };
    
    class Child01:public Parent
    {
    public:
        Child01()
        {
            cout << "Child01 construct" << endl;
        }
    
        virtual void overrideFunc()
        {
            cout << "Child01 override func" << endl;
        }
    };
    
    class Child02 :public Parent
    {
    public:
        Child02()
        {
            cout << "Child02 construct" << endl;
        }
    
        virtual void overrideFunc()
        {
            cout << "Child02 override func" << endl;
        }
    };
    
    void testMulStatus(Parent* p)    //想通过一个父类指针实现对子类对象方法的动态调用
    {
        p->overrideFunc();    //想实现对象方法的动态调用
    }
    
    void main()
    {
        Child01 c1;
        Child02 c2;
        testMulStatus(&c1);
        testMulStatus(&c2);
    
        system("pause");
    }

    四:原理探析(虚函数表指针VPtr)

    (一)多态中的虚函数表

    当类中声明虚函数时,编译器就会在类中生成一个虚函数表
    虚函数表是一个存储类成员虚函数指针的数据结构
    虚函数表由编译器自动生成和维护
    virtual成员函数会被编译器放入虚函数表中
    存在虚函数时,每个类中都会有一个指向虚函数表的指针(vptr指针)
    注意:虽然定义为虚函数,但是占用空间和原来成员函数大小是一样的,所以在内存上面唯一的区别在于多了一个虚函数指针(大小4字节)

    (二)证明虚函数指针的存在

    class Test
    {
    public:
        int a;
        int b;
    public:
        Test()
        {
    
        }
    
        void getInfo()
        {
            cout << "getInfo" << endl;
        }
    
        void setInfo()
        {
            cout << "setInfo" << endl;
        }
    };
    
    class Test02
    {
    public:
        int a;
        int b;
    public:
        Test02()
        {
    
        }
    
        virtual void getInfo()
        {
            cout << "getInfo" << endl;
        }
    
        virtual void setInfo()
        {
            cout << "setInfo" << endl;
        }
    };
    
    void main()
    {
        cout << sizeof(Test) << endl;
        cout << sizeof(Test02) << endl;
    
        system("pause");
    }

    无论是一个虚函数,还是两个或者多个虚函数,最终内存大小相差4字节。所以一个成员函数--->虚成员函数是不增加空间大小的。多的那4字节是由于虚函数表指针的增加导致的

    (三)多态上虚函数调用步骤

    每个对象会含有一个虚函数指针vptr,指向虚函数表,当父类指针调用重写虚函数时:首先会去找vptr,根据vptr去找对应的子类虚函数表,从而找到对应对象的方法进行调用

    (四)虚函数和普通函数调用的区别

    1.若是普通成员函数,编译器可以直接确定被调用成员函数(静态编链)
    2.若是虚函数:编译器要根据对象的vptr指针,找到虚函数表,找到对应的虚函数进行调用(动态编链)
    3.所以虚函数的调用效率要低于普通成员函数,所以出于效率,没有必要全部定义为虚函数

     

  • 相关阅读:
    解耦和耦合
    python os.remove()方法
    python中split()、os.path.split()函数用法
    P7116-[NOIP2020]微信步数【数学】
    2021牛客OI赛前集训营-方格计数【计数,dp】
    2021牛客OI赛前集训营-树数树【树上启发式合并,堆】
    Ybtoj-排列计数【矩阵乘法,分块幂】
    P7888-「MCOI-06」Distinct Subsequences【dp】
    号爸十一集训 Logs
    数据结构 专项题解
  • 原文地址:https://www.cnblogs.com/ssyfj/p/10775628.html
Copyright © 2011-2022 走看看