Skip to content

C++ 多态

多态是面向对象编程的核心特性之一,它允许使用统一的接口处理不同类型的对象。C++ 中的多态主要通过虚函数和继承来实现。

1. 多态的基本概念

多态是指同一个函数调用在不同对象上产生不同的行为。C++ 中的多态分为两种:

  • 编译时多态:通过函数重载和运算符重载实现
  • 运行时多态:通过虚函数和继承实现

2. 虚函数

虚函数是在基类中使用virtual关键字声明的成员函数,它在派生类中可以被重写。

2.1 虚函数的基本用法

cpp
#include <iostream>

class Animal {
public:
    virtual void make_sound() {
        std::cout << "动物发出声音" << std::endl;
    }
};

class Dog : public Animal {
public:
    void make_sound() override {
        std::cout << "狗叫" << std::endl;
    }
};

class Cat : public Animal {
public:
    void make_sound() override {
        std::cout << "猫叫" << std::endl;
    }
};

int main() {
    Animal* animal;
    
    Dog dog;
    Cat cat;
    
    animal = &dog;
    animal->make_sound();
    
    animal = &cat;
    animal->make_sound();
    
    return 0;
}

2.2 虚函数和普通函数的区别

cpp
#include <iostream>

class Base {
public:
    void normal_function() {
        std::cout << "基类的普通函数" << std::endl;
    }
    
    virtual void virtual_function() {
        std::cout << "基类的虚函数" << std::endl;
    }
};

class Derived : public Base {
public:
    void normal_function() {
        std::cout << "派生类的普通函数" << std::endl;
    }
    
    void virtual_function() override {
        std::cout << "派生类的虚函数" << std::endl;
    }
};

int main() {
    Base* base = new Derived();
    
    std::cout << "调用普通函数:" << std::endl;
    base->normal_function();
    
    std::cout << "调用虚函数:" << std::endl;
    base->virtual_function();
    
    delete base;
    
    return 0;
}

3. 纯虚函数和抽象类

3.1 纯虚函数

纯虚函数是在基类中声明的虚函数,它在基类中没有实现,必须在派生类中实现。

cpp
#include <iostream>

class Shape {
public:
    virtual double area() = 0;  // 纯虚函数
    virtual double perimeter() = 0;  // 纯虚函数
};

class Circle : public Shape {
private:
    double radius;

public:
    Circle(double radius) : radius(radius) {}
    
    double area() override {
        return 3.14159 * radius * radius;
    }
    
    double perimeter() override {
        return 2 * 3.14159 * radius;
    }
};

class Rectangle : public Shape {
private:
    double width;
    double height;

public:
    Rectangle(double width, double height) : width(width), height(height) {}
    
    double area() override {
        return width * height;
    }
    
    double perimeter() override {
        return 2 * (width + height);
    }
};

int main() {
    Shape* shape;
    
    Circle circle(5.0);
    Rectangle rectangle(4.0, 6.0);
    
    shape = &circle;
    std::cout << "圆的面积: " << shape->area() << std::endl;
    std::cout << "圆的周长: " << shape->perimeter() << std::endl;
    
    shape = &rectangle;
    std::cout << "矩形的面积: " << shape->area() << std::endl;
    std::cout << "矩形的周长: " << shape->perimeter() << std::endl;
    
    return 0;
}

3.2 抽象类

包含至少一个纯虚函数的类称为抽象类。抽象类不能被实例化,只能被继承。

cpp
#include <iostream>

class Animal {
public:
    virtual void make_sound() = 0;  // 纯虚函数
};

class Dog : public Animal {
public:
    void make_sound() override {
        std::cout << "狗叫" << std::endl;
    }
};

class Cat : public Animal {
public:
    void make_sound() override {
        std::cout << "猫叫" << std::endl;
    }
};

int main() {
    // Animal animal;  // 错误:抽象类不能被实例化
    
    Animal* animal;
    
    Dog dog;
    Cat cat;
    
    animal = &dog;
    animal->make_sound();
    
    animal = &cat;
    animal->make_sound();
    
    return 0;
}

4. 虚析构函数

当使用基类指针删除派生类对象时,应该将基类的析构函数声明为虚函数。

cpp
#include <iostream>

class Base {
public:
    Base() {
        std::cout << "基类构造函数" << std::endl;
    }
    
    virtual ~Base() {
        std::cout << "基类析构函数" << std::endl;
    }
};

class Derived : public Base {
public:
    Derived() {
        std::cout << "派生类构造函数" << std::endl;
    }
    
    ~Derived() {
        std::cout << "派生类析构函数" << std::endl;
    }
};

int main() {
    Base* base = new Derived();
    delete base;
    
    return 0;
}

5. 虚函数表

虚函数表(vtable)是 C++ 实现多态的机制。每个包含虚函数的类都有一个虚函数表,虚函数表中存储了该类的虚函数的地址。

cpp
#include <iostream>

class Base {
public:
    virtual void func1() {
        std::cout << "Base::func1" << std::endl;
    }
    
    virtual void func2() {
        std::cout << "Base::func2" << std::endl;
    }
};

class Derived : public Base {
public:
    void func1() override {
        std::cout << "Derived::func1" << std::endl;
    }
    
    void func2() override {
        std::cout << "Derived::func2" << std::endl;
    }
};

int main() {
    Base* base = new Derived();
    base->func1();
    base->func2();
    
    delete base;
    
    return 0;
}

6. 运算符重载和多态

cpp
#include <iostream>

class Shape {
public:
    virtual double area() = 0;
    virtual double perimeter() = 0;
    
    bool operator<(const Shape& other) {
        return area() < other.area();
    }
};

class Circle : public Shape {
private:
    double radius;

public:
    Circle(double radius) : radius(radius) {}
    
    double area() override {
        return 3.14159 * radius * radius;
    }
    
    double perimeter() override {
        return 2 * 3.14159 * radius;
    }
};

class Rectangle : public Shape {
private:
    double width;
    double height;

public:
    Rectangle(double width, double height) : width(width), height(height) {}
    
    double area() override {
        return width * height;
    }
    
    double perimeter() override {
        return 2 * (width + height);
    }
};

int main() {
    Circle circle(5.0);
    Rectangle rectangle(4.0, 6.0);
    
    if (circle < rectangle) {
        std::cout << "圆的面积小于矩形的面积" << std::endl;
    } else {
        std::cout << "圆的面积大于或等于矩形的面积" << std::endl;
    }
    
    return 0;
}

7. 示例:综合运用

现在,让我们看一个综合运用各种多态特性的例子:

cpp
#include <iostream>
#include <vector>

class Employee {
protected:
    std::string name;
    double salary;

public:
    Employee(std::string name, double salary) : name(name), salary(salary) {}
    
    virtual double calculate_salary() {
        return salary;
    }
    
    virtual void display() {
        std::cout << "姓名: " << name << std::endl;
        std::cout << "工资: " << calculate_salary() << std::endl;
    }
    
    virtual ~Employee() {}
};

class Manager : public Employee {
private:
    double bonus;

public:
    Manager(std::string name, double salary, double bonus) 
        : Employee(name, salary), bonus(bonus) {}
    
    double calculate_salary() override {
        return salary + bonus;
    }
    
    void display() override {
        std::cout << "经理:" << std::endl;
        Employee::display();
        std::cout << "奖金: " << bonus << std::endl;
    }
};

class Engineer : public Employee {
private:
    int overtime_hours;
    double overtime_rate;

public:
    Engineer(std::string name, double salary, int overtime_hours, double overtime_rate) 
        : Employee(name, salary), overtime_hours(overtime_hours), overtime_rate(overtime_rate) {}
    
    double calculate_salary() override {
        return salary + overtime_hours * overtime_rate;
    }
    
    void display() override {
        std::cout << "工程师:" << std::endl;
        Employee::display();
        std::cout << "加班小时数: " << overtime_hours << std::endl;
        std::cout << "加班费率: " << overtime_rate << std::endl;
    }
};

class Intern : public Employee {
public:
    Intern(std::string name, double salary) : Employee(name, salary) {}
    
    void display() override {
        std::cout << "实习生:" << std::endl;
        Employee::display();
    }
};

int main() {
    std::vector<Employee*> employees;
    
    employees.push_back(new Manager("张三", 10000.0, 2000.0));
    employees.push_back(new Engineer("李四", 8000.0, 10, 50.0));
    employees.push_back(new Intern("王五", 3000.0));
    
    for (Employee* employee : employees) {
        employee->display();
        std::cout << std::endl;
    }
    
    for (Employee* employee : employees) {
        delete employee;
    }
    
    return 0;
}

小结

C++ 多态包括:

  1. 多态的基本概念

    • 编译时多态:通过函数重载和运算符重载实现
    • 运行时多态:通过虚函数和继承实现
  2. 虚函数

    • 在基类中使用virtual关键字声明的成员函数
    • 在派生类中可以被重写
  3. 纯虚函数和抽象类

    • 纯虚函数:在基类中声明但没有实现的虚函数
    • 抽象类:包含至少一个纯虚函数的类
  4. 虚析构函数

    • 当使用基类指针删除派生类对象时,应该将基类的析构函数声明为虚函数
  5. 虚函数表

    • 虚函数表(vtable)是 C++ 实现多态的机制
    • 每个包含虚函数的类都有一个虚函数表
  6. 运算符重载和多态

    • 运算符重载可以与多态结合使用

关键概念:

  • 多态:同一个函数调用在不同对象上产生不同的行为
  • 虚函数:在基类中使用virtual关键字声明的成员函数
  • 纯虚函数:在基类中声明但没有实现的虚函数
  • 抽象类:包含至少一个纯虚函数的类
  • 虚析构函数:确保派生类的析构函数被正确调用
  • 虚函数表:C++ 实现多态的机制

掌握多态是 C++ 面向对象编程的重要基础,在后续章节中,我们将学习 C++ 的数据抽象。