
1. 什么是多态多态Polymorphism是面向对象编程的三大特性之一封装、继承、多态。它允许使用统一的接口来处理不同类型的对象具体执行哪个操作由对象的实际类型决定。在C中多态主要分为两种编译时多态静态多态通过函数重载和运算符重载实现在编译时就能确定调用哪个函数。运行时多态动态多态通过虚函数和继承实现在程序运行时根据对象的实际类型决定调用哪个函数。本文重点讨论运行时多态这是C面向对象编程中最核心的特性之一。2. 虚函数的工作原理虚函数virtual function是实现运行时多态的关键机制。当基类中的成员函数被声明为虚函数时派生类可以重写override该函数通过基类指针或引用调用时会根据实际指向的对象类型来调用相应的函数版本。2.1 虚函数表vtable每个包含虚函数的类都有一个虚函数表vtable这是一个函数指针数组存储了该类所有虚函数的地址。每个对象则包含一个指向其类vtable的指针vptr。2.2 虚函数声明与重写#include iostream using namespace std; // 基类 class Animal { public: // 虚函数声明 virtual void makeSound() { cout 动物发出声音 endl; } virtual ~Animal() {} // 虚析构函数 }; // 派生类 class Dog : public Animal { public: // 重写虚函数 void makeSound() override { cout 汪汪汪 endl; } }; // 另一个派生类 class Cat : public Animal { public: void makeSound() override { cout 喵喵喵 endl; } }; int main() { Animal* animal1 new Dog(); Animal* animal2 new Cat(); // 通过基类指针调用虚函数 animal1-makeSound(); // 输出汪汪汪 animal2-makeSound(); // 输出喵喵喵 delete animal1; delete animal2; return 0; }3. 多态的实现机制3.1 基类指针/引用的多态行为#include iostream #include vector using namespace std; class Shape { public: virtual double area() const 0; // 纯虚函数 virtual void draw() const { cout 绘制形状 endl; } virtual ~Shape() {} }; class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} double area() const override { return 3.14159 * radius * radius; } void draw() const override { cout 绘制圆形半径 radius endl; } }; class Rectangle : public Shape { private: double width, height; public: Rectangle(double w, double h) : width(w), height(h) {} double area() const override { return width * height; } void draw() const override { cout 绘制矩形宽 width 高 height endl; } }; int main() { vectorShape* shapes; shapes.push_back(new Circle(5.0)); shapes.push_back(new Rectangle(4.0, 6.0)); shapes.push_back(new Circle(3.0)); // 统一接口处理不同类型的对象 for (Shape* shape : shapes) { shape-draw(); cout 面积 shape-area() endl; } // 清理内存 for (Shape* shape : shapes) { delete shape; } return 0; }3.2 虚析构函数的重要性当通过基类指针删除派生类对象时如果基类析构函数不是虚函数只会调用基类的析构函数导致派生类部分的内存泄漏。class Base { public: virtual ~Base() { // 虚析构函数 cout Base析构函数 endl; } }; class Derived : public Base { public: ~Derived() { cout Derived析构函数 endl; } }; int main() { Base* ptr new Derived(); delete ptr; // 正确调用Derived和Base的析构函数 return 0; }4. 纯虚函数与抽象类纯虚函数是在基类中声明但没有定义的虚函数语法为virtual 返回类型 函数名(参数列表) 0;包含纯虚函数的类称为抽象类不能实例化对象只能作为基类被继承。// 抽象类 class Vehicle { public: virtual void start() 0; // 纯虚函数 virtual void stop() 0; // 纯虚函数 virtual ~Vehicle() {} }; class Car : public Vehicle { public: void start() override { cout 汽车启动 endl; } void stop() override { cout 汽车停止 endl; } }; class Bike : public Vehicle { public: void start() override { cout 自行车开始骑行 endl; } void stop() override { cout 自行车停止 endl; } };5. 多态的应用场景与优势5.1 应用场景插件系统统一接口动态加载不同插件GUI框架统一处理各种控件的事件游戏开发统一处理不同类型的游戏对象设计模式工厂模式、策略模式、观察者模式等5.2 优势代码复用通过基类接口统一处理扩展性新增派生类不影响现有代码灵活性运行时动态决定行为可维护性降低模块间的耦合度6. 注意事项只有通过指针或引用调用虚函数才会发生多态构造函数中调用虚函数不会发生多态此时vptr可能还未初始化内联函数不能是虚函数但编译器可能优化静态成员函数不能是虚函数友元函数不能是虚函数使用override关键字C11可以明确表示重写提高代码可读性使用final关键字C11可以禁止派生类重写7. 总结C的多态通过虚函数机制实现核心是虚函数表和虚函数指针。多态允许使用基类接口操作派生类对象提高了代码的灵活性、可扩展性和可维护性。正确使用虚函数、虚析构函数和纯虚函数是编写高质量面向对象C代码的关键。