Appearance
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++ 多态包括:
多态的基本概念:
- 编译时多态:通过函数重载和运算符重载实现
- 运行时多态:通过虚函数和继承实现
虚函数:
- 在基类中使用
virtual关键字声明的成员函数 - 在派生类中可以被重写
- 在基类中使用
纯虚函数和抽象类:
- 纯虚函数:在基类中声明但没有实现的虚函数
- 抽象类:包含至少一个纯虚函数的类
虚析构函数:
- 当使用基类指针删除派生类对象时,应该将基类的析构函数声明为虚函数
虚函数表:
- 虚函数表(vtable)是 C++ 实现多态的机制
- 每个包含虚函数的类都有一个虚函数表
运算符重载和多态:
- 运算符重载可以与多态结合使用
关键概念:
- 多态:同一个函数调用在不同对象上产生不同的行为
- 虚函数:在基类中使用
virtual关键字声明的成员函数 - 纯虚函数:在基类中声明但没有实现的虚函数
- 抽象类:包含至少一个纯虚函数的类
- 虚析构函数:确保派生类的析构函数被正确调用
- 虚函数表:C++ 实现多态的机制
掌握多态是 C++ 面向对象编程的重要基础,在后续章节中,我们将学习 C++ 的数据抽象。