C++中的多态是非常重要的一个概念。也是比较难理解的一个方面。***从字面意思理解,多态就是多种形态。***这也是非常常见的一种说法。
1.多态的引出
如下图所示,我们需要解决的问题就是计算几何图形的面积,然后定义了一个类Shape
,但是在具体实现的时候,各个图形的面积计算方法是不同的。
于是我们定义了不同的子类(图形),然后根据图形写出了面积的计算方法的代码:
#include <iostream> using namespace std; class Shape { protected: int width, height; public: Shape(int a = 0, int b = 0) { width = a; height = b; } int area() { cout << "Parent class area :" << endl; return 0; } }; class Rectangle : public Shape { public: Rectangle(int a = 0, int b = 0) :Shape(a, b) { } int area() { cout << "Rectangle class area :" << endl; return (width * height); } }; class Triangle : public Shape { public: Triangle(int a = 0, int b = 0) :Shape(a, b) { } int area() { cout << "Triangle class area :" << endl; return (width * height / 2); } }; // 程序的主函数 int main() { Shape *shape; Rectangle rec(10, 7); Triangle tri(10, 5); // 存储矩形的地址 shape = &rec; // 调用矩形的求面积函数 area //shape->area(); printf("\t---%d---\n", shape->area()); // 存储三角形的地址 shape = &tri; // 调用三角形的求面积函数 area //shape->area(); printf("\t---%d---\n", shape->area()); system("pause"); return 0; }
然而我们执行代码之后出现了如下的结果:
这是因为我们子类继承了父类的各种属性和方法,而在父类中area
方法的返回值是0
,因为调用函数 area() 被编译器设置为父类中的版本,这就是所谓的静态多态,或静态链接 - 函数调用在程序执行前就准备好了。有时候这也被称为早绑定。
2.虚函数
要实现我们理想的状态,就需要用到虚函数,也就是在父类的area方法前面加上virtual
关键字,代码如下:
#include <iostream> using namespace std; class Shape { protected: int width, height; public: Shape(int a = 0, int b = 0) { width = a; height = b; } virtual int area() { cout << "Parent class area :" << endl; return 0; } }; class Rectangle : public Shape { public: Rectangle(int a = 0, int b = 0) :Shape(a, b) { } int area() { cout << "Rectangle class area :" << endl; return (width * height); } }; class Triangle : public Shape { public: Triangle(int a = 0, int b = 0) :Shape(a, b) { } int area() { cout << "Triangle class area :" << endl; return (width * height / 2); } }; // 程序的主函数 int main() { Shape *shape; Rectangle rec(10, 7); Triangle tri(10, 5); // 存储矩形的地址 shape = &rec; // 调用矩形的求面积函数 area //shape->area(); printf("\t---%d---\n", shape->area()); // 存储三角形的地址 shape = &tri; // 调用三角形的求面积函数 area //shape->area(); printf("\t---%d---\n", shape->area()); system("pause"); return 0; }
运行结果为:
这就是多态的一般使用方式。有了多态,大大方便了我们代码的扩展。这种操作被称为动态链接,或后期绑定。
从这个例子就可以看出来,多态可以更加方便我们去根据不同的对象实现不同的方法,量体裁衣。
3.纯虚函数
从上面一个例子可以看出,父类的虚函数在每个子类中都做了实现,那就说明父类的虚函数并没有十分重要,那我们可不可以有一种更加简单的实现方式呢?
答案是有,就是纯虚函数。写法如下:
class Shape { protected: int width, height; public: Shape(int a = 0, int b = 0) { width = a; height = b; } virtual int area() = 0; };
理解起来也十分方便,就是令其为零,但是这个时候父类就变成了抽象类,抽象类是不能实例化的,通常用于实现接口的定理。比方说:
int main() { Shape shape(10,20); printf("宽度为:%d\n",shape.width); system("pause"); return 0; }
这个时候程序就会报错,提示:
4.拓展
从最基本的逻辑来说,如果父类定义了纯虚函数,如果子类不实现父类的纯虚函数,肯定是不行的。但是如果子类不实现父类的虚函数,情况又会如何呢?
答案是:会和我们的第一版代码一样,执行的时候返回0
。
-------------------------------------------------------------------------------------END------------------------------------------