简述一下 C++ 中的多态
多态(Polymorphism) 是面向对象编程(OOP)中的重要特性,它允许同一个接口(基类方法)在不同的对象上具有不同的行为。C++ 的多态可以分为 编译时多态(静态多态) 和 运行时多态(动态多态) 两种。
编译时多态是指在编译阶段就确定了调用哪个函数,主要包括:
同名函数,参数不同(参数类型或数量不同)
#include <iostream> using namespace std; class Example { public: void show(int x) { cout << "Integer: " << x << endl; } void show(double x) { cout << "Double: " << x << endl; } void show(string x) { cout << "String: " << x << endl; } }; int main() { Example ex; ex.show(10); // 调用 int 版本 ex.show(3.14); // 调用 double 版本 ex.show("Hello"); // 调用 string 版本 return 0; }
重载运算符,使其支持自定义数据类型
#include <iostream> using namespace std; class Complex { public: int real, imag; Complex(int r, int i) : real(r), imag(i) {} // 重载 + 运算符 Complex operator+(const Complex &c) { return Complex(real + c.real, imag + c.imag); } void display() { cout << real << " + " << imag << "i" << endl; } }; int main() { Complex c1(3, 4), c2(1, 2); Complex c3 = c1 + c2; // 使用重载的 + 运算符 c3.display(); // 输出:4 + 6i return 0; }
泛型编程,编译时确定类型
#include <iostream> using namespace std; template <typename T> T add(T a, T b) { return a + b; } int main() { cout << add(3, 4) << endl; // 7 (int) cout << add(3.5, 2.1) << endl; // 5.6 (double) return 0; }
运行时多态是在程序运行阶段决定调用哪个函数,主要依赖于虚函数(virtual functions)和动态绑定(dynamic binding)。
基类指针/引用指向派生类对象,并调用重写的方法
#include <iostream> using namespace std; class Base { public: virtual void show() { cout << "Base class" << endl; } // 虚函数 }; class Derived : public Base { public: void show() override { cout << "Derived class" << endl; } // 重写基类方法 }; int main() { Base* ptr; Derived obj; ptr = &obj; ptr->show(); // 运行时确定,调用 Derived::show() return 0; }
🔹 关键点
virtual关键字:告诉编译器该函数支持动态绑定(即运行时确定)。
基类指针指向子类对象,调用的方法由子类重写版本决定。
纯虚函数用于定义接口,强制子类必须实现该方法
#include <iostream> using namespace std; class Shape { public: virtual void draw() = 0; // 纯虚函数 }; class Circle : public Shape { public: void draw() override { cout << "Drawing Circle" << endl; } }; int main() { // Shape obj; // ❌ 抽象类不能实例化 Shape* shape = new Circle(); shape->draw(); // 调用 Circle 的 draw() delete shape; return 0; }
🔹 关键点
含有纯虚函数的类称为抽象类,不能实例化。
派生类必须实现纯虚函数,否则仍然是抽象类。
多态类型 | 主要机制 | 绑定方式 | 示例 |
---|---|---|---|
静态多态 | 函数重载、运算符重载、模板 | 编译时绑定 | void show(int),operator+,template<typename T> |
动态多态 | 继承 + 虚函数 | 运行时绑定 | virtual void show(),override |
静态多态 提高程序效率(编译时决定调用),但灵活性较低。
动态多态 提高程序扩展性(运行时决定调用),但有轻微性能开销。
✅ 应用场景
静态多态:适用于编译时确定类型的情况,如重载操作、模板。
动态多态:适用于需要运行时多态行为的场景,如 UI 组件绘制、策略模式等。
🚀 多态是面向对象编程的重要特性,使代码更具扩展性和可维护性!
得分点
静态多态、动态多态、多态的实现原理、虚函数、虚函数表
参考答案
标准回答
在现实生活中,多态是同一个事物在不同场景下的多种形态。在面向对象中,多态是指通过基类的指针或者引用,在运行时动态调用实际绑定对象函数的行为,与之相对应的编译时绑定函数称为静态绑定。所以多态分为静态多态和动态多态。
静态多态
静态多态是编译器在编译期间完成的,编译器会根据实参类型来选择调用合适的函数,如果有合适的函数就调用,没有的话就会发出警告或者报错。静态多态有函数重载、运算符重载、泛型编程等。
动态多态
动态多态是在程序运行时根据基类的引用(指针)指向的对象来确定自己具体该调用哪一个类的虚函数。当父类指针(引用)指向 父类对象时,就调用父类中定义的虚函数;即当父类指针(引用)指向 子类对象时,就调用子类中定义的虚函数。
加分回答
动态多态行为的表现效果为:同样的调用语句在实际运行时有多种不同的表现形态。
实现动态多态的条件:
动态多态的实现原理
当类中声明虚函数时,编译器会在类中生成一个虚函数表,虚函数表是一个存储类虚函数指针的数据结构,
虚函数表是由编译器自动生成与维护的。virtual 成员函数会被编译器放入虚函数表中,存在虚函数时,每个对象中都有一个指向虚函数表的指针(vptr 指针)。在多态调用时, vptr 指针就会根据这个对象在对应类的虚函数表中查找被调用的函数,从而找到函数的入口地址。