c++——多态

    技术2022-07-17  81

    一、多态的概念 简单来说,多态就是不同的对象做相同的事件有不同的结果和状态。

    二、多态的分类 1、静态多态(重载) 比如说函数重载:

    //进行加法运算 int Add(int x,int y){ return x+y; } double Add(double x,double y){ return x+y; } int main(){ int a=1; int b=2; double c=1.0; double d=2.0; cout<<Add(a,b)<<endl; cout<<Add(c,d)<<endl; return 0; }

    此外,还有运算符重载。在此不做过多介绍。

    由此可知,静态多态是编译器在编译期间完成的,编译器会根据参数的类型来选择调用对应的函数。

    2、动态多态 条件: (1)必须通过基类的指针或者引用调用虚函数 。 (2)被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写。

    #include<iostream> using namespace std; class A //基类 { public: int a; //基类中的a A(int x){ a = x; } virtual void Print1(){ cout << "基类1: " << a << endl; } void Print2(){ cout << "基类2: " << a << endl; } }; class B : public A //派生类 { public: int a; //派生类中的同名a B(int x,int y) :A(x){ a = y; } virtual void Print1(){ cout << "派生类1:" << a << endl; } void Print2(){ cout << "派生类2:" << a << endl; } }; void Test(A& p){ p.Print1(); p.Print2(); } int main(){ A p1(1); B p2(3,10); Test(p1); Test(p2); return 0; }

    由上面的结果可以看出,进行了虚函数重写的函数构成了多态,而没有进行虚函数重写则未构成多态。

    注: 重载:在同一个作用域,函数名和参数相同,参数类型不同。 重写:函数分别在基类和派生类的作用域中,函数名、参数、返回值都要相同,且函数为虚函数。(协变除外) 重定义:基类和派生类中的同名函数不构成重写就是重定义。

    协变(基类与派生类虚函数返回值类型不同) 当派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引 用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。

    3、抽象类 包含纯虚函数的类叫做抽象类(接口类),抽象类不能实例化对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。

    #include<iostream> using namespace std; class A //基类 { public: int a; //基类中的a A(int x){ a = x; } virtual void Print1() = 0; }; class B : public A //派生类 { public: int a; //派生类中的同名a B(int x,int y) :A(x){ a = y; } virtual void Print1(){ cout << "派生类1:" << a << endl; } }; void Test(A& p){ p.Print1(); } int main(){ A p1(1); //无法实现,抽象类不能实例化对象 B p2(3,10); //进行虚函数重写,可以实例化对象 Test(p1); Test(p2); system("pause"); return 0; }

    三、多态的原理 1、虚函数表

    class A { public: int a; A(int x){ a = x; } virtual void Print1() { cout << "基类1:" << a << endl; } }; int main(){ A p1(1); cout << sizeof(p1) << endl; system("pause"); return 0; }

    对于上面的这个类,我们可以求一下它的sizeof,会发现是8。那为什么不是4呢,它不是只有一个整形吗? 这是因为它除了自身所含有的内容外,它还有一个虚函数表指针——_vfptr。

    如果对B类也构建一个对象,会是什么情况呢你? 可以看到B类对象中也有一个虚表指针。

    由此我们就可以知道,多态的实现就是通过虚函数表指针去调用虚表中的虚函数来实现的。

    要注意的是,虚表中存放的是虚函数指针,而不是虚函数。此外,基类和派生类各有各的虚表,不是共用一个虚表。

    派生类虚表: 1.先对基类的虚表中的内容进行拷贝。 2.如果派生类对基类中的虚函数进行重写,使用派生类的虚函数替换相同偏移量位置的基类虚函数。 3.如果派生类中新增加自己的虚函数,按照其在派生类中的声明次序,放在上述虚函数之后。

    Processed: 0.016, SQL: 9