• C++中的多态


    一、学习笔记

    1.若子类中实现的函数和父类中的函数签名且函数名字一样,是复写。若函数参数不一样是重载。

    2.虚函数
    在函数声明前加virtual关键字的函数称为虚函数,若子类复写这个虚函数(前面加不加virtual声明无所谓),无论其前面有没有加virtual都是虚函数。

    3.多态中的虚函数编译器实现机制:动态链编个静态链编
    静态链编:非虚函数,编译时就确定好了调用哪一个函数。
    动态链编:运行时才确定是去调用哪一个函数,编译器实现原理:
    如果一个类中有虚函数,那么它的对象里面有一个虚函数指针,指向虚函数表,当去调用函数的时候,就通过这个虚函数指针调用虚函数表里面的虚函数。由于多了一个virtual指针,对象的大小变化了,可以使用sizeof(对象/类)查看。
    测试证明:多出一个指针大小,而且生成的可执行文件也变大了(此例中变大1/2)。

    4.使用虚函数时注意事项
    (1)只有在使用指针或引用来使用对象的时候会体现出多态,若是使用传值的方式不会体现出多态。eg:
    test_func(Human *h); //可以体现出多态
    test_func(Human &h); //可以体现出多态
    test_func(Human h); //不能体现出多态
    传值无法体现出多态的原因:例如Chinese是Human的子类,里面有继承Human的成员变量,还有自己的部分(包括虚函数指针),传值相当于直接将Chinese强制转化为Human,此时丢失了自己的部分(丢失了虚函数指针),因此无法表现出多态。

    (2)只有类的成员函数才能声明为虚函数

    (3)静态成员函数不能是虚函数

    (4)内联函数(inline修饰的函数)不能是虚函数,类中实现的函数一旦加上了virtual就不是内联函数了。

    (5)构造函数不能是虚函数。创建一个对象的时候立即就去调用了其构造函数,因此它能有什么多态。

    (6)析构函数一般都声明为虚函数。
    若父类的析构函数为虚函数,在delete父类指针(指向子类)的时候,会调用子类的析构函数,然后再调用父类的析构函数,尽管析构函数名字不同。
    这是一个特例

    (7)一般的子类重写虚函数需要函数签名和函数名字是一致的,但是返回值若为当前对象的指针或引用的时候(父类中的返回值是*Human/&Human)例外,
    此时这个函数也可以设置为虚函数。
    这是另一个特例

    (8)重载(参数不同)函数不能设置为虚函数。重写(函数签名和名字都相同)可以设置为虚函数。
    引用虚函数的目的是为了实现多态,多态就是若父类指针是指向之类的,就调用子类的方法。
    ==>但是实际测试父类中重载虚函数是没有问题的,子类中对父类中的虚函数进行重载也是没有问题的。

    二、Demo

    #include <iostream>
    
    using namespace std;
    
    
    class Human {
        int a;
    public:
        virtual void eating() {
            cout << "use hands" << endl;
        }
    
        //this is an exception,return Human*/&Human*
        virtual Human* return_test_ptr() {
            return this;
        }
        virtual Human& return_test_ref() {
            return *this;
        }
        virtual ~Human() {
            cout << "~Human()" << endl;
        }
    };
    
    
    class English : public Human {
    
    public:
        void eating() {
            cout << "use knifes" << endl;
        }
        English* return_test_ptr() {
            return this;
        }
        English& return_test_ref() {
            return *this;
        }
        ~English() {
            cout << "~English()" << endl;
        }
    };
    
    
    class Chinese : public Human {
    
    public:
        void eating() {
            cout << "use chopsticks" << endl;
        }
        Chinese* return_test_ptr() {
            return this;
        }
        Chinese& return_test_ref() {
            return *this;
        }
        ~Chinese() {
            cout << "~Chinese()" << endl;
        }
    };
    
    
    void eating_test(Human *h) {
        h->eating();
    }
    
    
    void pass_value_test(Human h) {
        h.eating();
    }
    
    void return_test_test(Human *h) {
        h->return_test_ptr()->eating();
        h->return_test_ref().eating();
    }
    
    void test_descructor(void) {
        Human *h = new Human();
        English *e = new English();
        Chinese *c = new Chinese();
    
        Human *ha[3] = {h, e, c};
    
        for (int i = 0; i < 3; i++) {
            ha[i]->eating();
            delete ha[i];
        }
    }
    
    int main() {
        Human h;
        English e;
        Chinese c;
    
        cout << "-----------eating_test-------------" << endl;
        eating_test(&h);
        eating_test(&e);
        eating_test(&c);
    
        cout << "---------pass_value_test-----------" << endl;
        pass_value_test(h);
        pass_value_test(e);
        pass_value_test(c);
    
        cout << "------------sizeof test------------" << endl;
        cout << "sizeof(h) = " << sizeof(h) << endl;
        cout << "sizeof(e) = " << sizeof(e) << endl;
        cout << "sizeof(c) = " << sizeof(c) << endl;
    
        cout << "---------return_test_test----------" << endl;
        return_test_test(&h);
        return_test_test(&e);
        return_test_test(&c);
    
        cout << "---------test_descructor-----------" << endl;
        test_descructor();
    
        cout << "------------exit main-------------" << endl;
    
        return 0;
    }
    
    
    
    /*
    ubuntu@ubuntu:~/Android_work/cpp_object/lesson2/Polymorphism$ ./pp
    -----------eating_test-------------
    use hands
    use knifes
    use chopsticks
    ---------pass_value_test-----------
    use hands
    ~Human()
    use hands
    ~Human()
    use hands
    ~Human()
    ------------sizeof test------------
    sizeof(h) = 16
    sizeof(e) = 16
    sizeof(c) = 16
    ---------return_test_test----------
    use hands
    use hands
    use knifes
    use knifes
    use chopsticks
    use chopsticks
    ---------test_descructor-----------
    use hands
    ~Human()
    use knifes
    ~English()
    ~Human()
    use chopsticks
    ~Chinese()
    ~Human()
    ------------exit main-------------
    ~Chinese()
    ~Human()
    ~English()
    ~Human()
    ~Human()
    
    */
  • 相关阅读:
    bzoj1202 狡猾的商人
    bzoj1059 矩阵游戏
    bzoj1003 物流运输
    bzoj1601 灌水
    2017-10-25模拟赛
    洛谷—— P1051 谁拿了最多奖学金
    BZOJ——1611: [Usaco2008 Feb]Meteor Shower流星雨
    2017-10-23学大伟业Day1
    BZOJ——1610: [Usaco2008 Feb]Line连线游戏
    Vijos 包裹快递(二分)
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10627958.html
Copyright © 2020-2023  润新知