C++ 继承(Inheritance)详细指南

1. 功能说明

本指南基于 inheritance.cpp 文件,详细介绍了 C++ 中继承的各种类型和用法,包括:

  • 基本继承:单继承的实现和使用
  • 多态:通过虚函数实现的运行时多态
  • 抽象类:包含纯虚函数的抽象基类
  • 多重继承:一个类同时继承多个基类
  • 虚继承:解决多重继承中的菱形继承问题
  • protected 继承:受保护的继承方式
  • private 继承:私有的继承方式

2. 代码解析

2.1 基本继承 - 动物类层次结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// 1. 动物基类 - 演示基本继承
class Animal {
protected:
std::string name; // 名称
int age; // 年龄

public:
// 构造函数
Animal(const std::string& n, int a) : name(n), age(a) {}

// 虚函数 - 发出声音
virtual void makeSound() const {
std::cout << "一些通用的动物声音" << std::endl;
}

// 虚函数 - 进食
virtual void eat() const {
std::cout << name << " 在吃东西" << std::endl;
}

// 普通成员函数 - 显示信息
void display() const {
std::cout << "名称: " << name << ", 年龄: " << age << std::endl;
}

// 虚析构函数
virtual ~Animal() {
std::cout << "动物析构函数被调用" << std::endl;
}
};

// 狗类 - 继承自动物类
class Dog : public Animal {
private:
std::string breed; // 品种

public:
// 构造函数
Dog(const std::string& n, int a, const std::string& b)
: Animal(n, a), breed(b) {}

// 重写虚函数 - 发出声音
void makeSound() const override {
std::cout << "汪汪!汪汪!" << std::endl;
}

// 特有成员函数 - 取物
void fetch() const {
std::cout << name << " 在取球" << std::endl;
}

// 重写显示信息函数
void display() const {
Animal::display();
std::cout << "品种: " << breed << std::endl;
}

// 析构函数
~Dog() {
std::cout << "狗析构函数被调用" << std::endl;
}
};

解析

  • Animal 是基类,包含了动物的基本属性和方法
  • Dog 是派生类,继承自 Animal,添加了特有的属性 breed 和方法 fetch()
  • 使用 protected 访问修饰符使得派生类可以访问基类的成员
  • virtual 关键字用于声明虚函数,支持运行时多态
  • override 关键字明确表示重写基类的虚函数
  • 虚析构函数确保派生类对象销毁时能正确调用基类的析构函数

2.2 抽象类 - 形状类层次结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 2. 形状抽象类 - 演示抽象类和纯虚函数
class Shape {
public:
// 纯虚函数 - 计算面积
virtual double area() const = 0;
// 纯虚函数 - 计算周长
virtual double perimeter() const = 0;
// 纯虚函数 - 显示信息
virtual void display() const = 0;

// 虚析构函数
virtual ~Shape() {}
};

// 圆形类 - 继承自形状类
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 display() const override {
std::cout << "圆形 - 半径: " << radius << std::endl;
std::cout << "面积: " << area() << std::endl;
std::cout << "周长: " << perimeter() << std::endl;
}
};

解析

  • Shape 是抽象基类,包含纯虚函数(通过 = 0 标记)
  • 纯虚函数没有实现,派生类必须提供实现
  • 抽象类不能直接实例化,只能作为基类使用
  • CircleRectangle 类实现了 Shape 中的所有纯虚函数

2.3 多重继承和虚继承 - 交通工具类层次结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// 3. 交通工具基类 - 用于多重继承示例
class Vehicle {
protected:
std::string brand; // 品牌
int year; // 年份

public:
// 构造函数
Vehicle(const std::string& b, int y) : brand(b), year(y) {}

// 虚函数 - 启动
virtual void start() const {
std::cout << "交通工具启动..." << std::endl;
}

// 虚函数 - 停止
virtual void stop() const {
std::cout << "交通工具停止..." << std::endl;
}

// 显示信息
void display() const {
std::cout << "品牌: " << brand << ", 年份: " << year << std::endl;
}

// 虚析构函数
virtual ~Vehicle() {}
};

// 汽车类 - 虚继承自交通工具类
class Car : virtual public Vehicle {
protected:
int numDoors; // 车门数量

public:
// 构造函数
Car(const std::string& b, int y, int doors)
: Vehicle(b, y), numDoors(doors) {}

// 重写虚函数 - 启动
void start() const override {
std::cout << "汽车引擎用钥匙启动" << std::endl;
}

// 特有成员函数 - 鸣笛
void honk() const {
std::cout << "嘟嘟!嘟嘟!" << std::endl;
}

// 重写显示信息函数
void display() const {
Vehicle::display();
std::cout << "车门数量: " << numDoors << std::endl;
}
};

// 电动类 - 虚继承自交通工具类
class Electric : virtual public Vehicle {
protected:
int batteryCapacity; // 电池容量(千瓦时)

public:
// 构造函数
Electric(const std::string& b, int y, int capacity)
: Vehicle(b, y), batteryCapacity(capacity) {}

// 特有成员函数 - 充电
void charge() const {
std::cout << "正在给电池充电..." << std::endl;
}

// 重写显示信息函数
void display() const {
Vehicle::display();
std::cout << "电池容量: " << batteryCapacity << " kWh" << std::endl;
}
};

// 电动汽车类 - 多重继承自汽车类和电动类
class ElectricCar : public Car, public Electric {
public:
// 构造函数
ElectricCar(const std::string& b, int y, int doors, int capacity)
: Vehicle(b, y), Car(b, y, doors), Electric(b, y, capacity) {}

// 重写虚函数 - 启动
void start() const override {
std::cout << "电动汽车安静地启动..." << std::endl;
}

// 重写显示信息函数
void display() const {
Car::display();
std::cout << "电池容量: " << batteryCapacity << " kWh" << std::endl;
}
};

解析

  • Vehicle 是基类,定义了交通工具的基本属性和方法
  • CarElectric 都虚继承自 Vehicle,使用 virtual 关键字
  • ElectricCar 多重继承自 CarElectric
  • 虚继承解决了菱形继承问题(即多个派生类继承同一个基类时的二义性)
  • ElectricCar 的构造函数中,需要显式调用 Vehicle 的构造函数

2.4 protected 继承 - 员工类层次结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 4. 员工基类 - 演示 protected 继承
class Employee {
protected:
std::string name; // 姓名
int employeeId; // 员工ID

public:
// 构造函数
Employee(const std::string& n, int id) : name(n), employeeId(id) {}

// 显示信息
void display() const {
std::cout << "员工姓名: " << name << ", ID: " << employeeId << std::endl;
}

// 虚析构函数
virtual ~Employee() {}
};

// 经理类 - protected 继承自员工类
class Manager : protected Employee {
private:
std::string department; // 部门

public:
// 构造函数
Manager(const std::string& n, int id, const std::string& dept)
: Employee(n, id), department(dept) {}

// 显示信息
void display() const {
Employee::display();
std::cout << "部门: " << department << std::endl;
}

// 管理方法
void manage() const {
std::cout << name << " 正在管理 " << department << " 部门" << std::endl;
}
};

解析

  • Manager 使用 protected 方式继承 Employee
  • protected 继承中,基类的 publicprotected 成员在派生类中变为 protected
  • 派生类可以访问基类的成员,但外部代码不能通过派生类对象访问基类的成员

2.5 private 继承 - 学生类层次结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 5. 学生基类 - 演示 private 继承
class Student {
protected:
std::string name; // 姓名
int studentId; // 学号

public:
// 构造函数
Student(const std::string& n, int id) : name(n), studentId(id) {}

// 显示信息
void display() const {
std::cout << "学生姓名: " << name << ", 学号: " << studentId << std::endl;
}

// 虚析构函数
virtual ~Student() {}
};

// 研究生类 - private 继承自学生类
class GraduateStudent : private Student {
private:
std::string researchArea; // 研究领域

public:
// 构造函数
GraduateStudent(const std::string& n, int id, const std::string& area)
: Student(n, id), researchArea(area) {}

// 显示信息
void display() const {
Student::display();
std::cout << "研究领域: " << researchArea << std::endl;
}

// 研究方法
void research() const {
std::cout << name << " 正在研究 " << researchArea << std::endl;
}
};

解析

  • GraduateStudent 使用 private 方式继承 Student
  • private 继承中,基类的 publicprotected 成员在派生类中变为 private
  • 只有派生类内部可以访问基类的成员,外部代码完全不能访问

2.6 主函数 - 测试各种继承场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
int main() {
std::cout << "=== 1. 动物继承 ===" << std::endl;
Dog dog("Buddy", 3, "金毛寻回犬");
Cat cat("Whiskers", 2, true);

dog.display();
dog.makeSound();
dog.eat();
dog.fetch();

std::cout << std::endl;

cat.display();
cat.makeSound();
cat.eat();
cat.climb();

std::cout << "\n=== 2. 使用动物指针的多态 ===" << std::endl;
Animal* animals[2];
animals[0] = new Dog("Max", 4, "拉布拉多");
animals[1] = new Cat("Mittens", 1, false);

for (int i = 0; i < 2; ++i) {
animals[i]->display();
animals[i]->makeSound();
delete animals[i];
}

std::cout << "\n=== 3. 抽象形状类 ===" << std::endl;
Shape* shapes[2];
shapes[0] = new Circle(5.0);
shapes[1] = new Rectangle(4.0, 6.0);

for (int i = 0; i < 2; ++i) {
shapes[i]->display();
delete shapes[i];
}

std::cout << "\n=== 4. 多重继承 ===" << std::endl;
ElectricCar tesla("Tesla", 2023, 4, 75);
tesla.display();
tesla.start();
tesla.honk();
tesla.charge();
tesla.stop();

std::cout << "\n=== 5. protected 继承 ===" << std::endl;
Manager manager("张三", 1001, "技术部");
manager.display();
manager.manage();

std::cout << "\n=== 6. private 继承 ===" << std::endl;
GraduateStudent gradStudent("李四", 2001, "人工智能");
gradStudent.display();
gradStudent.research();

return 0;
}

解析

  • 测试了基本继承、多态、抽象类、多重继承、protected 继承和 private 继承的使用
  • 通过基类指针指向派生类对象,演示了多态的实现
  • 展示了如何使用抽象类的指针来操作不同的派生类对象
  • 测试了多重继承的构造函数调用顺序和方法调用
  • 验证了 protected 继承和 private 继承的访问控制效果

3. 编译和运行说明

3.1 编译命令

使用以下命令编译 inheritance.cpp 文件:

1
g++ -std=c++11 -fexec-charset=GBK -o inheritance inheritance.cpp

参数说明:

  • -std=c++11:使用 C++11 标准
  • -fexec-charset=GBK:确保输出的中文字符正确显示
  • -o inheritance:指定输出可执行文件名为 inheritance

3.2 运行命令

编译成功后,使用以下命令运行程序:

1
2
./inheritance  # Linux/macOS
.\inheritance.exe # Windows

3.3 预期输出

运行程序后,您将看到类似以下的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
=== 1. 动物继承 ===
名称: Buddy, 年龄: 3
品种: 金毛寻回犬
汪汪!汪汪!
Buddy 在吃东西
Buddy 在取球

名称: Whiskers, 年龄: 2
室内猫: 是
喵喵!喵喵!
Whiskers 在吃东西
Whiskers 在爬树

=== 2. 使用动物指针的多态 ===
名称: Max, 年龄: 4
汪汪!汪汪!
狗析构函数被调用
动物析构函数被调用
名称: Mittens, 年龄: 1
喵喵!喵喵!
猫析构函数被调用
动物析构函数被调用

=== 3. 抽象形状类 ===
圆形 - 半径: 5
面积: 78.5397
周长: 31.4159
矩形 - 宽度: 4, 高度: 6
面积: 24
周长: 20

=== 4. 多重继承 ===
品牌: Tesla, 年份: 2023
车门数量: 4
电池容量: 75 kWh
电动汽车安静地启动...
嘟嘟!嘟嘟!
正在给电池充电...
交通工具停止...

=== 5. protected 继承 ===
员工姓名: 张三, ID: 1001
部门: 技术部
张三 正在管理 技术部 部门

=== 6. private 继承 ===
学生姓名: 李四, 学号: 2001
研究领域: 人工智能
李四 正在研究 人工智能
猫析构函数被调用
动物析构函数被调用
狗析构函数被调用
动物析构函数被调用

4. 技术要点

4.1 继承的基本概念

  • 继承是面向对象编程的三大特性之一(封装、继承、多态)
  • 继承允许创建一个新类(派生类),从一个或多个现有类(基类)中继承属性和方法
  • 继承的语法:class Derived : access-specifier Base,其中 access-specifier 可以是 publicprotectedprivate

4.2 访问控制

基类中的访问级别 public 继承 protected 继承 private 继承
public public protected private
protected protected protected private
private 不可访问 不可访问 不可访问

4.3 虚函数和多态

  • 虚函数:使用 virtual 关键字声明的函数,允许派生类重写
  • 多态:通过基类指针或引用调用虚函数时,会根据实际指向的对象类型调用相应的函数
  • override:C++11 引入的关键字,明确表示重写基类的虚函数
  • final:C++11 引入的关键字,防止虚函数被进一步重写或类被继承

4.4 抽象类和纯虚函数

  • 纯虚函数:声明为 virtual ReturnType function() const = 0; 的函数,没有实现
  • 抽象类:包含至少一个纯虚函数的类,不能直接实例化
  • 接口:只包含纯虚函数的抽象类,类似于 Java 或 C# 中的接口

4.5 多重继承和菱形继承问题

  • 多重继承:一个类同时继承多个基类,语法:class Derived : access-specifier Base1, access-specifier Base2
  • 菱形继承问题:当两个派生类继承同一个基类,而另一个类又同时继承这两个派生类时,会导致基类成员被重复继承
  • 虚继承:使用 virtual 关键字进行继承,确保基类只被继承一次,语法:class Derived : virtual public Base

4.6 构造函数和析构函数的调用顺序

  • 构造函数顺序:先调用基类构造函数,再调用派生类构造函数
  • 析构函数顺序:先调用派生类析构函数,再调用基类析构函数
  • 多重继承构造顺序:按照继承声明的顺序调用各基类的构造函数
  • 虚继承构造顺序:虚基类的构造函数在所有非虚基类之前调用

4.7 继承与组合的选择

  • 继承:表示 “is-a” 关系(例如,狗是一种动物)
  • 组合:表示 “has-a” 关系(例如,汽车有一个引擎)
  • 优先使用组合:组合通常比继承更灵活,减少了类之间的耦合
  • 继承的使用场景:当派生类确实是基类的一种特殊类型,并且需要多态行为时

5. 常见问题解答

5.1 什么是虚析构函数?为什么需要它?

虚析构函数是使用 virtual 关键字声明的析构函数。当通过基类指针删除派生类对象时,如果基类的析构函数不是虚函数,只会调用基类的析构函数,而不会调用派生类的析构函数,可能导致资源泄漏。

5.2 什么是菱形继承问题?如何解决?

菱形继承问题是指当两个派生类继承同一个基类,而另一个类又同时继承这两个派生类时,会导致基类成员被重复继承,产生二义性。

解决方法:使用虚继承(virtual public),确保基类只被继承一次。

5.3 public、protected 和 private 继承有什么区别?

  • public 继承:最常用的继承方式,表示 “is-a” 关系,基类的 public 成员在派生类中仍然是 public
  • protected 继承:表示 “is-implemented-in-terms-of” 关系的一种形式,基类的 public 和 protected 成员在派生类中变为 protected
  • private 继承:表示 “is-implemented-in-terms-of” 关系,基类的 public 和 protected 成员在派生类中变为 private

5.4 抽象类和接口有什么区别?

  • 抽象类:可以包含纯虚函数、虚函数和普通成员函数,也可以包含成员变量
  • 接口:在 C++ 中通常指只包含纯虚函数的抽象类,不包含任何成员变量和普通成员函数

5.5 什么时候应该使用多重继承?

多重继承应该谨慎使用,通常在以下情况下考虑:

  • 一个类需要同时具有多个不同类的行为
  • 实现多个接口(在 C++ 中通过继承多个只包含纯虚函数的抽象类)
  • 当组合无法满足需求时

5.6 如何在派生类中调用基类的构造函数和成员函数?

  • 调用基类构造函数:在派生类构造函数的初始化列表中,例如 Derived(int x) : Base(x) {}
  • 调用基类成员函数:使用作用域解析运算符 ::,例如 Base::function();

6. 代码优化建议

6.1 避免深层继承层次

  • 问题:深层继承层次会增加代码的复杂性,降低可维护性
  • 建议:保持继承层次不超过 3-4 层,超过时考虑使用组合或接口

6.2 优先使用组合而非继承

  • 问题:过度使用继承会导致类之间耦合过紧,难以修改
  • 建议:当不需要多态行为时,优先使用组合而非继承

6.3 正确使用虚函数和纯虚函数

  • 问题:不必要的虚函数会增加运行时开销
  • 建议:只在需要多态行为时使用虚函数,只在需要创建抽象类时使用纯虚函数

6.4 避免使用多重继承,除非必要

  • 问题:多重继承增加了代码的复杂性,可能导致二义性
  • 建议:优先使用单一继承和接口,只有在确实需要时才使用多重继承

6.5 使用 override 关键字明确重写

  • 问题:隐式重写可能导致错误,例如拼写错误或参数不匹配
  • 建议:在重写基类虚函数时,始终使用 override 关键字

6.6 合理设计构造函数和析构函数

  • 问题:不正确的构造函数和析构函数设计可能导致资源泄漏
  • 建议
    • 基类析构函数应声明为虚函数
    • 在构造函数中正确初始化所有成员
    • 在析构函数中释放所有获取的资源

6.7 使用 C++11 特性改进代码

  • 建议
    • 使用 overridefinal 关键字提高代码可读性和安全性
    • 使用智能指针管理动态内存,减少内存泄漏的风险
    • 使用 using 声明替代繁琐的 typedef
    • 使用 nullptr 替代 NULL 宏

7. 总结

继承是 C++ 中实现代码重用和多态的重要机制,通过本文的学习,您应该掌握了:

  • 基本继承的实现和使用
  • 多态的原理和应用
  • 抽象类和纯虚函数的使用
  • 多重继承和虚继承的概念
  • 不同继承方式(public、protected、private)的区别
  • 继承的最佳实践和常见陷阱

合理使用继承可以使代码更加模块化、可维护和可扩展,但也应该注意避免过度使用继承带来的问题。在实际开发中,应根据具体需求选择合适的设计方案,平衡继承和组合的使用。

inheritance.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
#include <iostream>
#include <string>

// 1. 动物基类 - 演示基本继承
class Animal {
protected:
std::string name; // 名称
int age; // 年龄

public:
// 构造函数
Animal(const std::string& n, int a) : name(n), age(a) {}

// 虚函数 - 发出声音
virtual void makeSound() const {
std::cout << "一些通用的动物声音" << std::endl;
}

// 虚函数 - 进食
virtual void eat() const {
std::cout << name << " 在吃东西" << std::endl;
}

// 普通成员函数 - 显示信息
void display() const {
std::cout << "名称: " << name << ", 年龄: " << age << std::endl;
}

// 虚析构函数
virtual ~Animal() {
std::cout << "动物析构函数被调用" << std::endl;
}
};

// 狗类 - 继承自动物类
class Dog : public Animal {
private:
std::string breed; // 品种

public:
// 构造函数
Dog(const std::string& n, int a, const std::string& b)
: Animal(n, a), breed(b) {}

// 重写虚函数 - 发出声音
void makeSound() const override {
std::cout << "汪汪!汪汪!" << std::endl;
}

// 特有成员函数 - 取物
void fetch() const {
std::cout << name << " 在取球" << std::endl;
}

// 重写显示信息函数
void display() const {
Animal::display();
std::cout << "品种: " << breed << std::endl;
}

// 析构函数
~Dog() {
std::cout << "狗析构函数被调用" << std::endl;
}
};

// 猫类 - 继承自动物类
class Cat : public Animal {
private:
bool isIndoor; // 是否是室内猫

public:
// 构造函数
Cat(const std::string& n, int a, bool indoor)
: Animal(n, a), isIndoor(indoor) {}

// 重写虚函数 - 发出声音
void makeSound() const override {
std::cout << "喵喵!喵喵!" << std::endl;
}

// 特有成员函数 - 爬树
void climb() const {
std::cout << name << " 在爬树" << std::endl;
}

// 重写显示信息函数
void display() const {
Animal::display();
std::cout << "室内猫: " << (isIndoor ? "是" : "否") << std::endl;
}

// 析构函数
~Cat() {
std::cout << "猫析构函数被调用" << std::endl;
}
};

// 2. 形状抽象类 - 演示抽象类和纯虚函数
class Shape {
public:
// 纯虚函数 - 计算面积
virtual double area() const = 0;
// 纯虚函数 - 计算周长
virtual double perimeter() const = 0;
// 纯虚函数 - 显示信息
virtual void display() const = 0;

// 虚析构函数
virtual ~Shape() {}
};

// 圆形类 - 继承自形状类
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 display() const override {
std::cout << "圆形 - 半径: " << radius << std::endl;
std::cout << "面积: " << area() << std::endl;
std::cout << "周长: " << perimeter() << std::endl;
}
};

// 矩形类 - 继承自形状类
class Rectangle : public Shape {
private:
double width; // 宽度
double 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 display() const override {
std::cout << "矩形 - 宽度: " << width << ", 高度: " << height << std::endl;
std::cout << "面积: " << area() << std::endl;
std::cout << "周长: " << perimeter() << std::endl;
}
};

// 3. 交通工具基类 - 用于多重继承示例
class Vehicle {
protected:
std::string brand; // 品牌
int year; // 年份

public:
// 构造函数
Vehicle(const std::string& b, int y) : brand(b), year(y) {}

// 虚函数 - 启动
virtual void start() const {
std::cout << "交通工具启动..." << std::endl;
}

// 虚函数 - 停止
virtual void stop() const {
std::cout << "交通工具停止..." << std::endl;
}

// 显示信息
void display() const {
std::cout << "品牌: " << brand << ", 年份: " << year << std::endl;
}

// 虚析构函数
virtual ~Vehicle() {}
};

// 汽车类 - 虚继承自交通工具类
class Car : virtual public Vehicle {
protected:
int numDoors; // 车门数量

public:
// 构造函数
Car(const std::string& b, int y, int doors)
: Vehicle(b, y), numDoors(doors) {}

// 重写虚函数 - 启动
void start() const override {
std::cout << "汽车引擎用钥匙启动" << std::endl;
}

// 特有成员函数 - 鸣笛
void honk() const {
std::cout << "嘟嘟!嘟嘟!" << std::endl;
}

// 重写显示信息函数
void display() const {
Vehicle::display();
std::cout << "车门数量: " << numDoors << std::endl;
}
};

// 电动类 - 虚继承自交通工具类
class Electric : virtual public Vehicle {
protected:
int batteryCapacity; // 电池容量(千瓦时)

public:
// 构造函数
Electric(const std::string& b, int y, int capacity)
: Vehicle(b, y), batteryCapacity(capacity) {}

// 特有成员函数 - 充电
void charge() const {
std::cout << "正在给电池充电..." << std::endl;
}

// 重写显示信息函数
void display() const {
Vehicle::display();
std::cout << "电池容量: " << batteryCapacity << " kWh" << std::endl;
}
};

// 电动汽车类 - 多重继承自汽车类和电动类
class ElectricCar : public Car, public Electric {
public:
// 构造函数
ElectricCar(const std::string& b, int y, int doors, int capacity)
: Vehicle(b, y), Car(b, y, doors), Electric(b, y, capacity) {}

// 重写虚函数 - 启动
void start() const override {
std::cout << "电动汽车安静地启动..." << std::endl;
}

// 重写显示信息函数
void display() const {
Car::display();
std::cout << "电池容量: " << batteryCapacity << " kWh" << std::endl;
}
};

// 4. 员工基类 - 演示 protected 继承
class Employee {
protected:
std::string name; // 姓名
int employeeId; // 员工ID

public:
// 构造函数
Employee(const std::string& n, int id) : name(n), employeeId(id) {}

// 显示信息
void display() const {
std::cout << "员工姓名: " << name << ", ID: " << employeeId << std::endl;
}

// 虚析构函数
virtual ~Employee() {}
};

// 经理类 - protected 继承自员工类
class Manager : protected Employee {
private:
std::string department; // 部门

public:
// 构造函数
Manager(const std::string& n, int id, const std::string& dept)
: Employee(n, id), department(dept) {}

// 显示信息
void display() const {
Employee::display();
std::cout << "部门: " << department << std::endl;
}

// 管理方法
void manage() const {
std::cout << name << " 正在管理 " << department << " 部门" << std::endl;
}
};

// 5. 学生基类 - 演示 private 继承
class Student {
protected:
std::string name; // 姓名
int studentId; // 学号

public:
// 构造函数
Student(const std::string& n, int id) : name(n), studentId(id) {}

// 显示信息
void display() const {
std::cout << "学生姓名: " << name << ", 学号: " << studentId << std::endl;
}

// 虚析构函数
virtual ~Student() {}
};

// 研究生类 - private 继承自学生类
class GraduateStudent : private Student {
private:
std::string researchArea; // 研究领域

public:
// 构造函数
GraduateStudent(const std::string& n, int id, const std::string& area)
: Student(n, id), researchArea(area) {}

// 显示信息
void display() const {
Student::display();
std::cout << "研究领域: " << researchArea << std::endl;
}

// 研究方法
void research() const {
std::cout << name << " 正在研究 " << researchArea << std::endl;
}
};

int main() {
std::cout << "=== 1. 动物继承 ===" << std::endl;
Dog dog("Buddy", 3, "金毛寻回犬");
Cat cat("Whiskers", 2, true);

dog.display();
dog.makeSound();
dog.eat();
dog.fetch();

std::cout << std::endl;

cat.display();
cat.makeSound();
cat.eat();
cat.climb();

std::cout << "\n=== 2. 使用动物指针的多态 ===" << std::endl;
Animal* animals[2];
animals[0] = new Dog("Max", 4, "拉布拉多");
animals[1] = new Cat("Mittens", 1, false);

for (int i = 0; i < 2; ++i) {
animals[i]->display();
animals[i]->makeSound();
delete animals[i];
}

std::cout << "\n=== 3. 抽象形状类 ===" << std::endl;
Shape* shapes[2];
shapes[0] = new Circle(5.0);
shapes[1] = new Rectangle(4.0, 6.0);

for (int i = 0; i < 2; ++i) {
shapes[i]->display();
delete shapes[i];
}

std::cout << "\n=== 4. 多重继承 ===" << std::endl;
ElectricCar tesla("Tesla", 2023, 4, 75);
tesla.display();
tesla.start();
tesla.honk();
tesla.charge();
tesla.stop();

std::cout << "\n=== 5. protected 继承 ===" << std::endl;
Manager manager("张三", 1001, "技术部");
manager.display();
manager.manage();

std::cout << "\n=== 6. private 继承 ===" << std::endl;
GraduateStudent gradStudent("李四", 2001, "人工智能");
gradStudent.display();
gradStudent.research();

return 0;
}