乐闻世界logo
搜索文章和话题

C++ 多态的实现机制有哪些

2月18日 17:33

C++ 多态的实现机制

多态是面向对象编程的核心特性之一,C++ 通过虚函数和继承机制实现了编译时多态和运行时多态。

多态的类型

1. 编译时多态(静态多态)

  • 函数重载
  • 运算符重载
  • 模板(泛型编程)

2. 运行时多态(动态多态)

  • 虚函数
  • 纯虚函数
  • 抽象类

虚函数实现多态

基本示例:

cpp
class Animal { public: virtual void makeSound() { std::cout << "Animal makes a sound" << std::endl; } virtual ~Animal() {} }; class Dog : public Animal { public: void makeSound() override { std::cout << "Dog barks" << std::endl; } }; class Cat : public Animal { public: void makeSound() override { std::cout << "Cat meows" << std::endl; } }; // 使用多态 void animalSound(Animal* animal) { animal->makeSound(); // 动态绑定 } int main() { Dog dog; Cat cat; animalSound(&dog); // 输出: Dog barks animalSound(&cat); // 输出: Cat meows return 0; }

纯虚函数与抽象类

纯虚函数:

cpp
class Shape { public: virtual double area() = 0; // 纯虚函数 virtual double perimeter() = 0; virtual ~Shape() {} // 虚析构函数 }; class Rectangle : public Shape { private: double width; double height; public: Rectangle(double w, double h) : width(w), height(h) {} double area() override { return width * height; } double perimeter() override { return 2 * (width + height); } }; class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} double area() override { return 3.14159 * radius * radius; } double perimeter() override { return 2 * 3.14159 * radius; } }; // 使用 void printShapeInfo(Shape* shape) { std::cout << "Area: " << shape->area() << std::endl; std::cout << "Perimeter: " << shape->perimeter() << std::endl; } int main() { Rectangle rect(5, 3); Circle circle(2); printShapeInfo(&rect); // Rectangle 的实现 printShapeInfo(&circle); // Circle 的实现 return 0; }

虚析构函数

为什么需要虚析构函数:

cpp
class Base { public: virtual ~Base() { std::cout << "Base destructor" << std::endl; } }; class Derived : public Base { private: int* data; public: Derived() : data(new int[100]) {} ~Derived() { delete[] data; std::cout << "Derived destructor" << std::endl; } }; // 正确使用 Base* ptr = new Derived(); delete ptr; // 正确调用 Derived 和 Base 的析构函数 // 如果 Base 的析构函数不是虚函数 class BaseNoVirtual { public: ~BaseNoVirtual() { // 非虚析构函数 std::cout << "BaseNoVirtual destructor" << std::endl; } }; class DerivedNoVirtual : public BaseNoVirtual { private: int* data; public: DerivedNoVirtual() : data(new int[100]) {} ~DerivedNoVirtual() { delete[] data; std::cout << "DerivedNoVirtual destructor" << std::endl; } }; // 错误使用 BaseNoVirtual* ptr2 = new DerivedNoVirtual(); delete ptr2; // 只调用 BaseNoVirtual 的析构函数,内存泄漏!

override 关键字

使用 override 确保正确重写:

cpp
class Base { public: virtual void func1() {} virtual void func2(int x) {} }; class Derived : public Base { public: void func1() override { // 正确重写 std::cout << "Derived func1" << std::endl; } // void func2() override; // 编译错误:参数不匹配 // void func3() override; // 编译错误:基类没有 func3 };

final 关键字

阻止进一步重写或继承:

cpp
class Base { public: virtual void func() final { // 不能被重写 std::cout << "Base func" << std::endl; } }; class Derived1 : public Base { public: // void func() override; // 编译错误:func 是 final }; class FinalClass final { // 不能被继承 public: void method() {} }; // class Derived2 : public FinalClass {}; // 编译错误:FinalClass 是 final

运行时类型识别(RTTI)

dynamic_cast:

cpp
class Animal { public: virtual ~Animal() {} }; class Dog : public Animal { public: void bark() { std::cout << "Woof!" << std::endl; } }; class Cat : public Animal { public: void meow() { std::cout << "Meow!" << std::endl; } }; void processAnimal(Animal* animal) { if (Dog* dog = dynamic_cast<Dog*>(animal)) { dog->bark(); } else if (Cat* cat = dynamic_cast<Cat*>(animal)) { cat->meow(); } } // 使用 Dog dog; Cat cat; processAnimal(&dog); // 输出: Woof! processAnimal(&cat); // 输出: Meow!

typeid:

cpp
#include <typeinfo> class Base { public: virtual ~Base() {} }; class Derived : public Base {}; int main() { Base* base = new Derived(); std::cout << "Type name: " << typeid(*base).name() << std::endl; std::cout << "Is Derived: " << (typeid(*base) == typeid(Derived)) << std::endl; delete base; return 0; }

多态的实际应用

策略模式:

cpp
class SortStrategy { public: virtual void sort(std::vector<int>& data) = 0; virtual ~SortStrategy() {} }; class BubbleSort : public SortStrategy { public: void sort(std::vector<int>& data) override { std::cout << "Using Bubble Sort" << std::endl; // 冒泡排序实现 } }; class QuickSort : public SortStrategy { public: void sort(std::vector<int>& data) override { std::cout << "Using Quick Sort" << std::endl; // 快速排序实现 } }; class Sorter { private: SortStrategy* strategy; public: void setStrategy(SortStrategy* s) { strategy = s; } void sort(std::vector<int>& data) { strategy->sort(data); } }; // 使用 Sorter sorter; BubbleSort bubbleSort; QuickSort quickSort; std::vector<int> data = {5, 2, 8, 1, 9}; sorter.setStrategy(&bubbleSort); sorter.sort(data); // 使用冒泡排序 sorter.setStrategy(&quickSort); sorter.sort(data); // 使用快速排序

观察者模式:

cpp
class Observer { public: virtual void update(const std::string& message) = 0; virtual ~Observer() {} }; class Subject { private: std::vector<Observer*> observers; public: void attach(Observer* observer) { observers.push_back(observer); } void detach(Observer* observer) { observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end()); } void notify(const std::string& message) { for (auto observer : observers) { observer->update(message); } } }; class EmailObserver : public Observer { public: void update(const std::string& message) override { std::cout << "Email: " << message << std::endl; } }; class SMSObserver : public Observer { public: void update(const std::string& message) override { std::cout << "SMS: " << message << std::endl; } }; // 使用 Subject subject; EmailObserver emailObserver; SMSObserver smsObserver; subject.attach(&emailObserver); subject.attach(&smsObserver); subject.notify("Hello World!"); // 输出: // Email: Hello World! // SMS: Hello World!

编译时多态

函数重载:

cpp
class Printer { public: void print(int value) { std::cout << "Int: " << value << std::endl; } void print(double value) { std::cout << "Double: " << value << std::endl; } void print(const std::string& value) { std::cout << "String: " << value << std::endl; } }; // 使用 Printer printer; printer.print(42); // 调用 print(int) printer.print(3.14); // 调用 print(double) printer.print("Hello"); // 调用 print(string)

运算符重载:

cpp
class Complex { private: double real; double imag; public: Complex(double r = 0, double i = 0) : real(r), imag(i) {} Complex operator+(const Complex& other) const { return Complex(real + other.real, imag + other.imag); } Complex operator*(const Complex& other) const { return Complex(real * other.real - imag * other.imag, real * other.imag + imag * other.real); } friend std::ostream& operator<<(std::ostream& os, const Complex& c) { os << c.real << " + " << c.imag << "i"; return os; } }; // 使用 Complex c1(1, 2); Complex c2(3, 4); Complex sum = c1 + c2; Complex product = c1 * c2; std::cout << sum << std::endl; // 4 + 6i std::cout << product << std::endl; // -5 + 10i

模板(静态多态):

cpp
template <typename T> T add(T a, T b) { return a + b; } // 使用 int intResult = add(10, 20); // T = int double doubleResult = add(3.14, 2.71); // T = double // CRTP(奇异递归模板模式) template <typename Derived> class Base { public: void interface() { static_cast<Derived*>(this)->implementation(); } }; class Derived : public Base<Derived> { public: void implementation() { std::cout << "Derived implementation" << std::endl; } }; // 使用 Derived d; d.interface(); // 输出: Derived implementation

最佳实践

1. 始终为多态基类声明虚析构函数

cpp
class Base { public: virtual ~Base() = default; // 虚析构函数 };

2. 使用 override 关键字确保正确重写

cpp
class Derived : public Base { public: void func() override { // 明确表示重写 // 实现 } };

3. 优先使用组合而非继承

cpp
// 推荐:组合 class Engine { public: void start() { std::cout << "Engine started" << std::endl; } }; class Car { private: Engine engine; public: void start() { engine.start(); } }; // 不推荐:过度继承 class Vehicle { public: virtual void start() = 0; }; class Car : public Vehicle { public: void start() override { std::cout << "Car started" << std::endl; } };

4. 避免过度使用 dynamic_cast

cpp
// 不推荐 if (Dog* dog = dynamic_cast<Dog*>(animal)) { dog->bark(); } else if (Cat* cat = dynamic_cast<Cat*>(animal)) { cat->meow(); } // 推荐:使用虚函数 class Animal { public: virtual void makeSound() = 0; }; class Dog : public Animal { public: void makeSound() override { bark(); } void bark() { std::cout << "Woof!" << std::endl; } };

注意事项

  • 虚函数调用有性能开销,避免在性能关键路径过度使用
  • 构造函数和析构函数中调用虚函数不会发生动态绑定
  • 不要在构造函数中调用纯虚函数
  • 虚函数不能是静态成员函数
  • 避免在基类构造函数中调用虚函数
  • 考虑使用 final 关键字阻止不必要的重写
  • 谨慎使用 RTTI,它可能影响性能和可维护性
标签:C++