多态

什么是多态?

多态(Polymorphism)是指,在编程语言中用某个单一的记号来表示多个类型。这个定义非常广泛,只要满足“一个记号”“多种类型“两个条件的任何语法都可以被称为多态。比如:

  • 特设多态(Ad-hoc polymorphism),即函数重载。同一个名字的函数可能拥有不同的参数类型,这就是多态;
  • 参数多态(Parametric polymorphism),即模板泛型。它也是指用一个函数名或类名来表示“一堆”函数或类,下一章将展开讲解。
  • 子类型多态(Subtype polymorphism)。在面向对象编程中,基类的指针或者引用可以持有派生类对象,而这个派生类可以是不同的类型。这时,一个基类指针或引用可以同时表现出不同派生类的性质,这也是多态;
  • 列多态(Row polymorphism),即鸭子类型多态。在一些语言(如 JavaScript),同一个函数可以作用于任何“成员名字相同”的类型(被称为“鸭子类型”)。此时,这个函数的参数也体现了多态的性质。

很显然,这一节我们主要处理的是子类型多态,即通过基类和派生类之间的继承关系来体现多态的实现和作用。

多态的时机

对于 C++ 这种编译型语言,其多态可能发生在编译时期,也可能发生在运行时期。比如,特设多态(函数重载)就发生在编译期间——换句话说,编译期间就能确定某个名字的类型:

void f(int) { }
void f(const char*) { }
int main() {
    f(3);    // 这里 f 的类型编译期间就能确定,是 void(int)
    f("hi"); // 这里 f 的类型编译期间就能确定,是 void(const char*)
}

而子类型多态并不一定能在编译期间就能确定类型:

#include <iostream>
struct B {};
// D1 和 D2 都继承自 B
struct D1 : B {};
struct D2 : B {};
int main() {
    B* ptr{nullptr};
    D1 d1; D2 d2;
    int x;
    std::cin >> x;
    if (x == 0) {
        ptr = &d1;
    } else {
        ptr = &d2;
    }
    // 现在,ptr 所指向的实际类型编译期间是无法确定的
    // 它依赖于输入的 x 值,有可能指向不同的类型
    ptr;
}

像特设多态这种能在编译期间确定类型的被称为编译期多态,而像子类型多态这种不一定能在编译期间确定类型的被称为运行期多态

最近更新:
代码未运行