zoukankan      html  css  js  c++  java
  • 8、多态与继承


    1、多态

        多态是通过虚函数来实现的,也就是说虚函数是允许子类重新定义成员函数,而子类通过定义和父类一样的函数的方法,被成为覆盖或者是重写。

        多态的作用,使得代码可以重用,代码模块化;

    函数重写:

        (1)子类定义的函数与父类原型相同的函数

        (2)函数的重写只有发生在父类和子类之间

    class Parent 
    {
    public:
        void f()
        {
            cout << "Parent" << endl;
        }
    };
    class Child : public Parent
    {
    public:
        void f()
        {
            cout << "Child" << endl;
        }
    };
    int main()
    {
        Child c1;
        c1.f();
        while (1);
    }

     

        打印出子类的同名函数:Child,除非使用 c1.Parent::f(); 才会执行 父类的打印函数,一般的情况是,编译器会将父类的打印函数进行隐藏,使用的是子函数重写的函数去执行,

    void run()
    {
        Child c1;
        c1.f();
        Parent *pp = &c1;
        pp->f(); // 父类的打印
        Parent &ppp = c1;
        ppp.f(); // 父类的打印
    }
    int main()
    {
        run();
        while (1);
    }

    打印出来:

    Child
    Parent
    Parent

        打印结果,居然和分析不一样,原因是:C和C++是静态编译型语言(编译器会根据指针的类型去判断执行的是一个什么用的对象),所以,我们的指针和引用的是 是 Parent,所以执行的时候,输出的结果是父类的打印函数。言而总之,总而言之,我们就看指针,指针是什么类型。

    多态的本质:

        通过添加 virtual 关键字对多态进行支持,将会被子类进行重写的函数,前面加上 virtual 关键字,

    class Parent 
    {
    public:
        virtual void f()
        {
            cout << "Parent" << endl;
        }
    };
    class Child : public Parent
    {
    public:
        virtual void f()
        {
            cout << "Child" << endl;
        }
    };
    void run()
    {
        Child c1;
        c1.f();
        Parent *pp = &c1;
        pp->f();
        Parent &ppp = c1;
        ppp.f();
    }
    这三个打印输出的就是: child child child

        只要在会被进行函数重写的函数假如 virtual 关键字,那么这个函数就是虚函数,到具体使用的时候,就会根据实际的情况进行打印输出。传入的是什么类型的,打印的就是什么类型的。

    重载和重写的区别:什么时候重载、什么时候重写

        (1)重载:

        A 是同时存在多个同名的函数,但是在参数的个数,参数的类型、参数的顺序存在区别,

        B 事实上,重载只能发生在一个类里面,继承是不能实现函数的重载。

        C 原理上,C++编译器根据参数的不同,重新生成函数名,所以不同的参数会生成不同的函数名,所以本质上就是不同的函数了,也就是说编译器在编译的时候,就已经可以区分到底调用的是哪一个重载的函数,编译器早早已经确定,这些函数的编译的时候的地址就已经是被绑定了(早绑定)。

        (2)重写:

        A 是指子类重新定义父类的虚函数。子类重新定义了父类的虚函数,

         B 必须是发生在父类和子类之间。 父类和子类中的函数,必须完全相同的原型

        C 使用 virtual 可以产生多态

        D 多态是在运行的期间跟根据具体的对象的类型决定调用函数。

    将所有的函数都加上 virtual 关键字:

        完全没有必要,这就涉及到虚函数的实现编译器将包含了 virtual 的虚函数的函数信息,存放到虚函数表里面,每次运行的时候,都会去虚函数表里面进行比对,看看是不是虚函数,如果是的话,那么就使用虚函数表里面的函数,不是的话,就去运行类内部其他的函数,所以不要将所有的函数全部设置为虚函数,会造成大量的浪费,处于效率考虑的话,其实就不要全部设置为虚函数。

    纯虚函数:

        是一种特殊的虚函数,在基类中(父类)不能对虚函数给据有意义的实现,而把他声明为纯虚函数,它的实现则留给子类去做,这就是纯虚函数的作用,

        纯虚函数在父类只做函数原型的声明,而故意不定义函数体的虚函数,函数的定义等子类去完成(必须),这样就完成了纯虚函数的作用。

    class Shape 
    {
    public: // 纯虚函数声明,没有实际的意义
        virtual double area() = 0;
    };
    class Rectangle : public Shape
    {
        double a;
        double b;
    public:
        Rectangle(double a, double b)
        {
            this->a = a;
            this->b = b;
        }
        // 函数的重写,纯虚函数重写
        double area()
        {
            return a * b;
        }
        
    };
    void area(Shape *s)
    {
        cout << s->area() << endl;
    }
    void run()
    {
        Rectangle rectangle(3, 4);
        cout<<"area is "<<rectangle.area()<<endl;
        area(&rectangle); // 可以使用指针
        //Shape shape; // 不能定义抽象类
    }

       看到纯虚函数的声明是,virtual 函数 = 0; 告诉编译器,这个只是声明,所以必须在子类去实现这个函数;注意到: 抽象类(shape,包含了一个纯虚函数的类)已经是不能定义对象了,但是仍然可以使用指针。

    注意:

        不要将多态应用于数组当中,

    多重继承:

        多重继承就是 子类既继承自父类1,同时也继承父类2。实际的应用中,是不使用多重继承,

  • 相关阅读:
    day7 面向对象 静态方法 类方法 属性方法 类的特殊成员方法 元类 反射 异常处理
    day6 面向对象 封装 继承 多态 类与实例在内存中的关系 经典类和新式类
    day5 time datetime random os sys shutil json pickle shelve xml configparser hashlib subprocess logging re正则 python计算器
    kafka常用操作命令
    linux基础
    django学习1——初识web应用程序
    mysql数据库(三)——pymysql模块
    mysql数据库(二)——表的查询
    mysql数据库(一)
    Python常用模块——re模块
  • 原文地址:https://www.cnblogs.com/qxj511/p/5217594.html
Copyright © 2011-2022 走看看