C++笔记(面向对象)多态(编译时 运行时)

1. 多态的基本概念

多态(Polymorphism) = "多种形态",指同一个接口在不同情况下表现出不同的行为。

两种多态类型:

  • 编译时多态(静态多态):在编译期间确定具体调用哪个函数

  • 运行时多态(动态多态):在运行期间确定具体调用哪个函数


2. 编译时多态(Static Polymorphism)

编译时多态在编译阶段就确定了具体调用的函数,主要通过以下机制实现:

2.1 函数重载(Function Overloading)

cpp

复制代码
#include <iostream>
using namespace std;

class Calculator {
public:
    // 函数重载:同名函数,参数列表不同
    int add(int a, int b) {
        cout << "调用 add(int, int)" << endl;
        return a + b;
    }
    
    double add(double a, double b) {
        cout << "调用 add(double, double)" << endl;
        return a + b;
    }
    
    int add(int a, int b, int c) {
        cout << "调用 add(int, int, int)" << endl;
        return a + b + c;
    }
    
    string add(const string& a, const string& b) {
        cout << "调用 add(string, string)" << endl;
        return a + b;
    }
};

int main() {
    Calculator calc;
    
    cout << calc.add(1, 2) << endl;           // 调用 add(int, int)
    cout << calc.add(1.5, 2.5) << endl;       // 调用 add(double, double)
    cout << calc.add(1, 2, 3) << endl;        // 调用 add(int, int, int)
    cout << calc.add("Hello", "World") << endl; // 调用 add(string, string)
    
    return 0;
}

输出:

text

复制代码
调用 add(int, int)
3
调用 add(double, double)
4
调用 add(int, int, int)
6
调用 add(string, string)
HelloWorld

特点:

  • 编译时根据参数类型和数量决定调用哪个函数

  • 函数名相同,参数列表必须不同

  • 返回类型不同不足以构成重载

2.2 运算符重载(Operator Overloading)

cpp

复制代码
class Complex {
private:
    double real, 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);
    }
    
    void display() const {
        cout << real << " + " << imag << "i" << endl;
    }
};

int main() {
    Complex c1(3.0, 4.0), c2(1.0, 2.0);
    
    Complex c3 = c1 + c2;  // 编译时确定调用 operator+
    Complex c4 = c1 - c2;  // 编译时确定调用 operator-
    
    c3.display();  // 4 + 6i
    c4.display();  // 2 + 2i
    
    return 0;
}

2.3 模板(Templates)

cpp

复制代码
// 函数模板 - 编译时实例化
template<typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}

// 类模板 - 编译时实例化
template<typename T>
class Container {
private:
    T value;
public:
    Container(T v) : value(v) {}
    T getValue() const { return value; }
};

int main() {
    // 编译时生成具体函数
    cout << max(10, 20) << endl;        // 生成 max<int>
    cout << max(3.14, 2.71) << endl;    // 生成 max<double>
    cout << max('a', 'z') << endl;      // 生成 max<char>
    
    // 编译时生成具体类
    Container<int> intContainer(100);     // 生成 Container<int>
    Container<string> strContainer("Hello"); // 生成 Container<string>
    
    return 0;
}

3. 运行时多态(Dynamic Polymorphism)

运行时多态在程序运行期间确定具体调用的函数,主要通过虚函数实现:

3.1 虚函数机制

cpp

复制代码
#include <iostream>
#include <vector>
#include <memory>
using namespace std;

class Animal {
public:
    // 虚函数 - 实现运行时多态
    virtual void speak() const {
        cout << "Animal speaks" << endl;
    }
    
    virtual void eat() const {
        cout << "Animal eats" << endl;
    }
    
    // 虚析构函数 - 重要!
    virtual ~Animal() {
        cout << "Animal destructor" << endl;
    }
};

class Dog : public Animal {
public:
    void speak() const override {
        cout << "Woof! Woof!" << endl;
    }
    
    void eat() const override {
        cout << "Dog eats bone" << endl;
    }
    
    ~Dog() override {
        cout << "Dog destructor" << endl;
    }
};

class Cat : public Animal {
public:
    void speak() const override {
        cout << "Meow! Meow!" << endl;
    }
    
    void eat() const override {
        cout << "Cat eats fish" << endl;
    }
    
    ~Cat() override {
        cout << "Cat destructor" << endl;
    }
};

class Bird : public Animal {
public:
    void speak() const override {
        cout << "Chirp! Chirp!" << endl;
    }
    
    void eat() const override {
        cout << "Bird eats seeds" << endl;
    }
    
    ~Bird() override {
        cout << "Bird destructor" << endl;
    }
};

// 多态函数:接受基类引用,实际调用派生类函数
void animalConcert(const Animal& animal) {
    animal.speak();  // 运行时确定调用哪个speak
}

int main() {
    vector<unique_ptr<Animal>> animals;
    animals.push_back(make_unique<Dog>());
    animals.push_back(make_unique<Cat>());
    animals.push_back(make_unique<Bird>());
    
    cout << "=== 多态演示 ===" << endl;
    for (const auto& animal : animals) {
        animal->speak();  // 运行时多态
        animal->eat();    // 运行时多态
        cout << "---" << endl;
    }
    
    cout << "=== 通过基类引用 ===" << endl;
    Dog dog;
    Cat cat;
    Bird bird;
    
    animalConcert(dog);  // 输出: Woof! Woof!
    animalConcert(cat);  // 输出: Meow! Meow!
    animalConcert(bird); // 输出: Chirp! Chirp!
    
    return 0;
}

输出:

text

复制代码
=== 多态演示 ===
Woof! Woof!
Dog eats bone
---
Meow! Meow!
Cat eats fish
---
Chirp! Chirp!
Bird eats seeds
---
=== 通过基类引用 ===
Woof! Woof!
Meow! Meow!
Chirp! Chirp!
Dog destructor
Animal destructor
Cat destructor
Animal destructor
Bird destructor
Animal destructor

3.2 纯虚函数与抽象类

cpp

复制代码
// 抽象类 - 包含纯虚函数
class Shape {
public:
    // 纯虚函数 - 接口定义
    virtual double area() const = 0;
    virtual double perimeter() const = 0;
    virtual void draw() const = 0;
    
    // 虚析构函数
    virtual ~Shape() = default;
};

class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    
    double area() const override {
        return 3.14159 * radius * radius;
    }
    
    double perimeter() const override {
        return 2 * 3.14159 * radius;
    }
    
    void draw() const override {
        cout << "Drawing Circle with radius " << 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;
    }
    
    double perimeter() const override {
        return 2 * (width + height);
    }
    
    void draw() const override {
        cout << "Drawing Rectangle " << width << "x" << height << endl;
    }
};

void printShapeInfo(const Shape& shape) {
    shape.draw();
    cout << "Area: " << shape.area() << ", Perimeter: " << shape.perimeter() << endl;
}

int main() {
    Circle circle(5.0);
    Rectangle rectangle(4.0, 6.0);
    
    printShapeInfo(circle);     // 运行时多态
    printShapeInfo(rectangle);  // 运行时多态
    
    return 0;
}

总结:运行时的多态性: 公有继承 + 虚函数 + (指针或引用调用虚函数)。


4. 两种多态的对比

对比表格:

特性 编译时多态 运行时多态
确定时间 编译期间 运行期间
实现机制 函数重载、运算符重载、模板 虚函数、继承
性能 高效,无运行时开销 有轻微性能开销(vtable查找)
灵活性 相对较低 很高,支持动态绑定
代码体积 可能较大(模板实例化) 相对较小
典型应用 通用算法、数学运算 框架设计、插件系统

5.总结

编译时多态:

  • ✅ 高性能,无运行时开销

  • ✅ 类型安全,编译期检查

  • ❌ 灵活性较低

  • ❌ 代码可能膨胀(模板)

运行时多态:

  • ✅ 高灵活性,支持动态绑定

  • ✅ 接口统一,易于扩展

  • ❌ 有性能开销(vtable查找)

  • ❌ 需要虚析构函数确保安全

选择准则:

  • 需要高性能类型安全 → 编译时多态

  • 需要灵活扩展动态行为 → 运行时多态

  • 大型框架和系统 → 结合使用两种多态

相关推荐
晨非辰6 小时前
《数据结构风云》递归算法:二叉树遍历的精髓实现
c语言·数据结构·c++·人工智能·算法·leetcode·面试
太理摆烂哥6 小时前
map&&set的使用
c++·stl
Dream it possible!6 小时前
LeetCode 面试经典 150_链表_LRU 缓存(66_146_C++_中等)(哈希表 + 双向链表)
c++·leetcode·链表·面试
mailangduoduo6 小时前
命令行传参及调试——vscode平台
c++·人工智能·vscode·代码调试·命令行传参
敲上瘾6 小时前
Linux系统C++开发工具(四)—— jsoncpp 使用指南
linux·服务器·网络·c++·json
ceclar1236 小时前
C++日期与时间
开发语言·c++
Minecraft红客6 小时前
复原大唐3d项目测试版
c++·3d·青少年编程·电脑·娱乐
小-黯7 小时前
OpenGL使用C++实现相机模块功能
c++·3d·opengl
_dindong8 小时前
牛客101:二叉树
数据结构·c++·笔记·学习·算法