C++ 多态(一)
Polymorphism in C++
概述
多态这个词的意思是有多种形式。通常,多态发生在类的层次结构中,它们通过继承相互关联。
C++ 多态意味着对成员函数的调用将导致执行不同的函数,这取决于调用该函数的对象类型。
实例
考虑下面的例子,其中一个基类 Shape,由其派生出两个派生类:Rectangle 和 Triangle。
#include <iostream>
using namespace std;
class Shape
{
public:
Shape(int a = 0, int b = 0)
{
width = a;
height = b;
}
int area()
{
cout << "Parent class area :" <<endl;
return 0;
}
protected:
int width, height;
};
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;
// 调用计算矩形面积函数
shape->area();
// 存储三角形对象的地址
shape = &tri;
// 调用计算三角形面积函数
shape->area();
return 0;
}
编译并执行上述代码时,将产生如下结果:
Parent class area :
Parent class area :
输出错误的原因是,函数 area() 的调用被编译器设置为基类中定义的版本。这被称为函数调用的静态解析,或静态链接——函数调用在程序执行之前是固定的。这有时也称为早期绑定,因为 area() 函数是在程序编译期间设置的。
但是现在,让我们在程序中做一点修改,在 Shape 类中使用关键字 virtual 声明在 area() 之前,使它看起来像这样:
class Shape
{
public:
Shape(int a = 0, int b = 0)
{
width = a;
height = b;
}
virtual int area()
{
cout << "Parent class area :" <<endl;
return 0;
}
protected:
int width, height;
};
经过这一轻微修改后,在编译和执行前面的示例代码时,将产生以下结果:
Rectangle class area :
Triangle class area :
这一次,编译器查看指针的内容,而不是它的类型。因此,由于 tri 和 recc 类对象的地址存储在 *shape 中,因此分别调用 area() 函数。
如您所见,每个子类都有一个单独的函数 area() 实现。多态通常就是这样使用的。您拥有具有相同名称的函数的不同类,甚至具有相同的参数,但具有不同的实现。
虚函数
虚函数是基类中使用关键字 virtual 声明的函数。在基类中定义虚函数,在派生类中定义另一个版本,会向编译器发出这样的信号:我们不希望该函数使用静态链接。
我们想要的是在程序中任意给定的点上根据被调用对象的类型来选择要调用的函数。这种操作称为动态链接或后期绑定。
纯虚函数
有可能您希望在基类中包含虚函数,以便在派生类中重新定义它,以适合该类的对象,但在基类中没有为该函数提供有意义的定义。
我们可以将基类中的虚函数 area() 更改为如下:
class Shape
{
public:
Shape(int a = 0, int b = 0)
{
width = a;
height = b;
}
// 纯虚函数
virtual int area() = 0;
protected:
int width, height;
};
“= 0” 告诉编译器该函数没有函数体,上面的虚函数将被称为纯虚函数。