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------------------------------------------------------------------