多态

    技术2022-07-10  144

    一.构成多态的条件 1.继承 2.在父类中定义了虚函数,且在子类中完成了对该函数的重写 3.通过子类的指针或者引用调用该虚函数

    其中虚函数为被关键字virtual修饰的函数,其格式为:virtual 返回值类型 函数名(形参列表){函数体}

    二.重写与同名隐藏 1.同名隐藏 同名隐藏是指在子类中定义了和父类中同名的变量或者函数,其中函数只要函数名相同,不论函数的返回值和形参列表是否相同。此时父类中同名的函数被隐藏,若需要调用父类中同名的函数需要加上父类的作用域。 2.函数重写 只针对虚函数而言。不仅要求函数名相同,而且函数的返回值和形参列表必须完全相同(协变和析构函数例外)。其中只需要在父类中函数前加上关键字virtual,而子类中重写该函数时即使不加上关键字virtual也构成对该函数的重写,但是尽量加上virtual以提高程序的可读性。 (1)协变 协变是指若父类的虚函数的返回值是父类对象的指针或者引用,子类中重写该函数时返回类型为子类对象的指针或引用,此时也构成函数重写。 (2)析构函数的重写 对于析构函数,父类和子类对象函数名看起来不可能相同,无法构成重写。但是编译器在底层做了特殊处理,使得父类和子类的析构函数是同名的。因此只需要在父类的析构函数前加上关键字virtual,子类对象的析构函数便构成了对父类析构函数的重写。

    三.override和final

    在形参列表之后、函数体之前添加关键字override表示该函数必须重写父类的某个虚函数,若在父类虚函数处添加final关键字则表示该函数不可以被重写。

    class T1 { public: virtual void fun() final {} virtual void fun2() {} }; class T2 : public T1{ public: //virtual void fun() {} //无法重写父类中被final修饰的虚函数 virtual void fun2(int) //override 必须重写父类中的某个函数 { cout << "T2 :: fun2()" << endl; } };

    四.抽象类 包含纯虚函数的类成为抽象类。其中纯虚函数是指没有函数体的虚函数,只包含了函数的返回值、函数名和形参列表,且以=0结束声明的函数: virtual 返回值类型 函数名(形参列表)=0; 纯虚函数可以在函数体外进行定义,但是没有实际意义。因为编译器根据声明已经认为其为纯虚函数。

    抽象类无法实例化对象,因为只有声明而没有实际的函数体。若子类继承了抽象类而没有重写虚函数,也不能实例化对象,只有重写了纯虚函数之后才可以实例化对象。因为子类继承父类,虚表中的纯虚函数也是没有函数体的。

    五.虚表与虚表指针 若父类中或者子类中有虚函数,则通常会在子类对象的头四个字节存放一个虚表指针。指向一个函数指针数组,用于存放从父类中继承而来的虚函数和子类中新定义的虚函数指针。其中虚函数表中存放的顺序为先按照父类中虚函数的声明顺序存放父类虚函数的函数指针,在按照子类中新定义的虚函数函数指针。若在子类中完成了对父类虚函数的重写,则会将虚函数表中该父类虚函数的函数指针替换为子类虚函数的函数指针。虚表只存放子类和父类中的虚函数指针,不存放普通函数的函数指针。

    若子类继承了多个直接父类,则会存在和直父类个数一致的虚表。虚表指针存放的位置为该父类成员存放位置之前。若子类中重写了父类中的虚函数,仍然会将虚表中函数指针替换为子类虚函数的指针。若在子类中重新定义虚函数,则会将新定义的虚函数指针添加到第一张虚函数表之后。

    Processed: 0.011, SQL: 9