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。实际的应用中,是不使用多重继承,

  • 相关阅读:
    大数据之路Week10_day01 (练习:通过设计rowkey来实现查询需求)
    大数据之路Week10_day01 (通过直接创建Hfile文件的方式往Hbase中插入数据)
    大数据之路Week10_day01 (Hbase总结 II)
    Week09_day05(Java API操作Hbase)
    Week09_day05(Hbase的基本使用)
    Zookeeper、Hadoop、Hbase的启动顺序以及关闭顺序
    Week09_day05(Hbase的安装搭建)
    HDU 1198
    hdu 1250 Hat's Fibonacci(java,简单,大数)
    HDU 1316 How Many Fibs?(java,简单题,大数)
  • 原文地址:https://www.cnblogs.com/qxj511/p/5217594.html
Copyright © 2011-2022 走看看