多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异,而采用不同的策略。
虚函数和纯虚函数都是实现多态的重要方法。本文就这两种方法进行分析以及比较
1、虚函数
在基类中声明为 virtual 并在一个或者多个派生类被重新定义的成员函数
语法规则:virtual 函数返回类型 函数名(参数表) {函数体}
语法分析:虚函数的声明和定义和普通的成员函数一样,只是在返回值之前加入了关键字virtual。
在基类当中定义了虚函数,可以再子类中定义和基类中相同函数名、相同参数、相同返回值和不同实现体的虚函数
定义为虚函数是为了让基类函数的指针或者引用来指向子类。
#include<iostream> using namespace std; class A { public: void fun() { cout << "A::fun()..." << endl; } }; class B :public A { public: void fun() { cout << "B::fun()...." << endl; } }; int main() { A *a = new A; //A类指针指向A类对象 a->fun(); A *b = new B; //A类指针指向B类 对象 b->fun(); delete a; delete b; return 0; }
分析代码:在上述代码中B为A的派生类,A *b=new B 是将基类的指针指向B 类对象。输出为:
显然程序没有实现我们想要的输出
#include<iostream> using namespace std; class A { public: virtual void fun() { cout << "A::fun()..." << endl; } }; class B :public A { public: void fun() { cout << "B::fun()...." << endl; } }; int main() { A *a = new A; //A类指针指向A类对象 a->fun(); A *b = new B; //A类指针指向B类 对象 b->fun(); delete a; delete b; return 0; }
分析:可以看出利用虚函数可以实现多态,也就是说实现了通过不同对象的接口实现了不同的功能。
在使用虚函数是需要注意:
1、不能被声明为虚函数是函数类型有:构造函数,内联函数,静态成员函数
2、与构造函数不同,析构函数要尽量使用虚函数,当派生类的对象从内存中撤销的时候,会先调用派生类的析构函数然后再调用基类的析构函数,delete撤销对象时只调用了基类的析构函数,而没有执行派生类的析构函数。对此,我们将基类的析构函数声明为虚函数。
3、在基类方法声明中使用关键字virtual,可以是相同函数名(返回值、函数名、参数表)在所有的派生类中是虚函数。
2、纯虚函数
在一些情况中,基类不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现由它的派生类去做。
语法规则:virtual 返回值 函数名(参数表)=0;
语法分析:纯虚函数可以让类先具有一个实现功能的名字,没有给出具体实现该功能的方法。凡是含有纯虚函数的类都叫抽象类
这种类不能声明对象,只能作为基类去被继承,由子类去重写函数体,实现函数功能。
#include<iostream> using namespace std; class Shope { public: virtual double GetArea() = 0; //定义为纯虚函数 virtual double GetCir() = 0; //定义为纯虚函数 }; class Circle :public Shope { public: Circle(float r):r(r){} double GetArea() //函数重写 { return r * r*3.14; } double GetCir() //函数重写 { return 3.14 * 2 * r; } private: float r; }; class Rectangle :public Shope { public: Rectangle(float a,float b):a(a),b(b){} double GetArea() //函数重写 { return a * b; } double GetCir() //函数重写 { return (a + b) * 2; } private: float a; float b; }; int main() { Shope *ci = new Circle(4); //基类指针指向Circle对象 cout << "半径为4的圆周长为" << ci->GetCir() << ",面积为" << ci->GetArea() << endl; Shope *rec = new Rectangle(4.2, 5.3);//基类指针指向Rectangle对象 cout << "长为4.2,宽为5.3的矩形,周长为" << rec->GetCir() << ",面积为" << rec->GetArea() << endl; return 0; }
分析:在shope类中,声明的两个纯虚函数,GetArea(),GetCir();Circle类和Rectangle类去继承基类,重写纯虚函数。
根据不同的形状,由不同的计算周长和面积的方法,具体实现方法需要派生类自己去重载。
使用纯虚函数的注意:
1、纯虚函数一定没有定义,它是用来规范派生类的行为,即接口。包含纯虚函数的抽象类,不能定义实例,但是可以声明指向该抽象类的具体类的指针或者引用
2、基类的纯虚函数在派生类中必须全部定义,否则派生类依然是抽象类,无法实例化。
3、总结
1、纯虚函数是特殊的虚函数,在纯虚函数中,同样可以让基类的指针指向子类对象。
2、纯虚函数:只提供一个接口,具体实现方法需要派生类自己去重载
虚函数:提供接口,并提供默认的实现方法;派生类也可以根据需要自己去重载
两者区别:纯虚函数在基类中不会提供实现方法,而虚函数需要提供。
原文地址:https://www.cnblogs.com/aaakihi/p/11743050.html