多态性意味着,被调用者是当它收到来自调用者的消息时决定如何做的人。
想一个消息“前进 10 米”。如果被调用者是人,则该人通过步行来完成。如果被调用者是汽车,则汽车通过转动车轮来实现。
多态性的概念并没有具体说明涉及哪些语言特征,或者何时决定如何做。我们可以在运行时使用虚函数来实现。我们可以在编译时(静态多态性),使用函数重载、模板,甚至邪恶的预处理器宏来实现。
如果我们使用虚函数:
MovableObject* ptr = get_person();
ptr->go_forward(10);
MovableObject* ptr2 = get_car();
ptr2->go_forward(10);
如果我们使用函数重载:
void go_forward(Person& person, int distance);
void go_forward(Car& car, int distance);
并非所有函数重载都用作多态。
要通过重载演示静态多态性,请考虑两个简单的程序。
// Program 1
int a;
int b;
std::cin >> a >> b;
int sum = a + b;
std::cout << sum;
// Program 2
double a;
double b;
std::cin >> a >> b;
double sum = a + b;
std::cout << sum;
等等。看起来它不涉及重载,是吗?
实际上,有超载。这两个程序都涉及表达式a + b。它们都意味着对我们的补充。但有一点不同:程序1中的+被编译成整数加法的机器指令;程序 2 中的+ 被编译为浮点加法。两者都是加法,但物理运算却大不相同。
是否超载?是的,+ 已超载。
是多态吗?是的,+ 对于这两种情况的调用者来说意味着同样的事情,并且底层操作是不同的。
现在考虑+ 的另一种用法。
// Program 3
std::string a;
std::string b;
std::cin >> a >> b;
std::string sum = a + b;
std::cout << sum;
程序 3 也使用+。但它不再是添加。现在是字符串连接。
是否超载?是的,+ 已超载。
是多态吗?不,与程序 1 和 2 相比,现在的含义有所不同。加法和连接是非常不同的东西。
另一个例子。
想想标准库容器。
vector<int> my_vector;
begin(my_vector);
list<double> my_list;
begin(my_list);
是否超载?是的,begin 已超载。
是多态吗?是的,begin 的两个版本都返回一个指向第一个元素的迭代器,即使迭代器的类型不同。
这个怎么样。一个代表秒表的类,一个函数begin开始计时。
Stopwatch my_watch;
begin(my_watch);
是否超载?是的,begin 已超载。
是多态吗?这次不行。这个begin 不是为了获取迭代器。它只是启动秒表。意思不同,所以和其他begins一起考虑时不是一种多态形式。