前言
本文主要探讨C++中多态的实现原理并通过一个简单的示例实现多态。
一、什么是多态?
多态分为编译时的多态和运行时的多态
1. 静态联编—编译时的多态
在程序编译时期就确定好的根据函数名和参数列表确定程序在运行时调用哪个函数,比如说函数重载。
2. 动态联编—运行时的多态
在程序运行时根据实际情况决定调用哪个函数,它是通过类的公有继承关系中的虚函数实现的,具体来讲就是虚函数表与虚函数指针的应用。
当一个类中含有虚函数时,在编译期间会给这个类分配一段连续的内存空间 (虚函数表—vftable) 来存放虚函数的地址,类中只保存指向 vftable 的虚函数指针— vfptr。在有虚函数的类被继承后,编译器会给派生类重新分配一段内存空间,派生类通过从基类继承下来的 vfptr 将基类的 vftable 拷贝到这段内存空间并将其中同名的虚函数地址修改为自己重写的虚函数地址。这样,当使用基类的指针或引用调用一个虚函数的时候,程序就会根据实际的对象来选择相应的虚函数从而实现多态。
二、虚函数与纯虚函数
1. 定义
虚函数: 被关键字 virtual 修饰的类的成员函数称为虚函数。
纯虚函数: 在虚函数后面添加 “= 0” 。
虚函数与纯虚函数的作用都是实现多态,即基类访问派生类成员函数。
2. 虚函数与纯虚函数的区别
- 从定义上来讲,被关键字 virtual 修饰的类的成员函数称为虚函数,而纯虚函数为在虚函数后面添加 “= 0”。
- 虚函数在派生类可以重写也可以不重写,纯虚函数必须重写以保证接口的统一性。
- 带纯虚函数的类称为抽象类,不能被实例化,而只含虚函数的类不能被称为抽象类。
三、实现多态
1. 示例代码
#include <iostream>
using namespace std;
/*基类 图形*/
class Shape {
public:
Shape(int a, int b)
{
width = a;
height = b;
}
virtual int area() = 0;
protected:
int width;
int height;
};
/*派生类 三角形*/
class Triangle : public Shape {
public:
Triangle(int a, int b):Shape(a, b) {}
int area()
{
cout << "Triangle area:" << (width * height) / 2 << endl;
return (width * height / 2);
}
};
/*派生类 矩形*/
class Rectangle : public Shape {
public:
Rectangle(int a, int b):Shape(a, b) {}
int area()
{
cout << "Rectangle area:" << (width * height) << endl;
return (width * height);
}
};
int main(int argc, char *argv[])
{
//Shape s(10, 20);//拥有纯虚函数的基类无法实例化
Shape *ptr;
Rectangle rec(10, 20);
Triangle tri(10, 20);
ptr = &rec;
ptr->area();
ptr = &tri;
ptr->area();
return 0;
}