实验4

一、实验任务1

源代码task1

  1 #include <algorithm>
  2 #include <array>
  3 #include <cstdlib>
  4 #include <iomanip>
  5 #include <iostream>
  6 #include <numeric>
  7 #include <string>
  8 #include <vector>
  9 
 10 #include "GradeCalc.hpp"
 11 
 12 GradeCalc::GradeCalc(const std::string &cname):course_name{cname},is_dirty{true} {
 13     counts.fill(0);
 14     rates.fill(0);   
 15 }
 16 
 17 void GradeCalc::input(int n) {
 18     if(n < 0) {
 19         std::cerr << "无效输入! 人数不能为负数\n";
 20         std::exit(1);
 21     }
 22 
 23     grades.reserve(n);
 24 
 25     int grade;
 26 
 27     for(int i = 0; i < n;) {
 28         std::cin >> grade;
 29 
 30         if(grade < 0 || grade > 100) {
 31             std::cerr << "无效输入! 分数须在[0,100]\n";
 32             continue;
 33         }
 34         
 35         grades.push_back(grade);
 36         ++i;
 37     }
 38 
 39     is_dirty = true;  // 设置脏标记:成绩信息有变更
 40 }
 41 
 42 void GradeCalc::output() const {
 43     for(auto grade: grades)
 44         std::cout << grade << ' ';
 45     std::cout << std::endl;
 46 }
 47     
 48 void GradeCalc::sort(bool ascending) {
 49     if(ascending)
 50         std::sort(grades.begin(), grades.end());
 51     else
 52         std::sort(grades.begin(), grades.end(), std::greater<int>());
 53 }
 54 
 55 int GradeCalc::min() const {
 56     if(grades.empty())
 57         return -1;
 58 
 59     auto it = std::min_element(grades.begin(), grades.end());
 60     return *it;
 61 }
 62 
 63 int GradeCalc::max() const {
 64     if(grades.empty()) 
 65         return -1;
 66 
 67     auto it = std::max_element(grades.begin(), grades.end());
 68     return *it;
 69 }
 70 
 71 double GradeCalc::average() const {
 72     if(grades.empty())
 73         return 0.0;
 74 
 75     double avg = std::accumulate(grades.begin(), grades.end(), 0.0)/grades.size();
 76     return avg;
 77 }
 78 
 79 void GradeCalc::info() {
 80     if(is_dirty) 
 81        compute();
 82 
 83     std::cout << "课程名称:\t" << course_name << std::endl;
 84     std::cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() << std::endl;
 85     std::cout << "最高分:\t" << max() << std::endl;
 86     std::cout << "最低分:\t" << min() << std::endl;
 87 
 88     const std::array<std::string, 5> grade_range{"[0, 60) ", 
 89                                            "[60, 70)", 
 90                                            "[70, 80)",
 91                                            "[80, 90)", 
 92                                            "[90, 100]"};
 93     
 94     for(int i = static_cast<int>(grade_range.size())-1; i >= 0; --i)
 95         std::cout << grade_range[i] << "\t: " << counts[i] << "人\t"
 96                   << std::fixed << std::setprecision(2) << rates[i]*100 << "%\n";
 97 }
 98 
 99 void GradeCalc::compute() {
100     if(grades.empty())
101         return;
102 
103     counts.fill(0); 
104     rates.fill(0.0);
105 
106     // 统计各分数段人数
107     for(auto grade:grades) {
108         if(grade < 60)
109             ++counts[0];        // [0, 60)
110         else if (grade < 70)
111             ++counts[1];        // [60, 70)
112         else if (grade < 80)
113             ++counts[2];        // [70, 80)
114         else if (grade < 90)
115             ++counts[3];        // [80, 90)
116         else
117             ++counts[4];        // [90, 100]
118     }
119 
120     // 统计各分数段比例
121     for(size_t i = 0; i < rates.size(); ++i)
122         rates[i] = counts[i] * 1.0 / grades.size();
123     
124     is_dirty = false;  // 更新脏标记
125 }
GradeCalc.cpp
 1 #pragma once
 2 
 3 #include <vector>
 4 #include <array>
 5 #include <string>
 6 
 7 class GradeCalc {
 8 public:
 9     GradeCalc(const std::string &cname);      
10     void input(int n);                         // 录入n个成绩
11     void output() const;                      // 输出成绩
12     void sort(bool ascending = false);        // 排序 (默认降序)
13     int min() const;                          // 返回最低分(如成绩未录入,返回-1)
14     int max() const;                          // 返回最高分 (如成绩未录入,返回-1)
15     double average() const;                   // 返回平均分 (如成绩未录入,返回0.0)
16     void info();                      // 输出课程成绩信息 
17 
18 private:
19     void compute();     // 成绩统计
20 
21 private:
22     std::string course_name;     // 课程名
23     std::vector<int> grades;     // 课程成绩
24     std::array<int, 5> counts;      // 保存各分数段人数([0, 60), [60, 70), [70, 80), [80, 90), [90, 100]
25     std::array<double, 5> rates;    // 保存各分数段人数占比 
26     bool is_dirty;      // 脏标记,记录是否成绩信息有变更
27 };
GradeCalc.hpp
 1 #include <iostream>
 2 #include <string>
 3 #include "GradeCalc.hpp"
 4 
 5 void test() {
 6     GradeCalc c1("OOP");
 7 
 8     std::cout << "录入成绩:\n";
 9     c1.input(5);
10 
11     std::cout << "输出成绩:\n";
12     c1.output();
13 
14     std::cout << "排序后成绩:\n";
15     c1.sort(); c1.output();
16 
17     std::cout << "*************成绩统计信息*************\n";
18     c1.info();
19 
20 }
21 
22 int main() {
23     test();
24 }
task1.cpp

运行结果截图

bb1c90b11fa26d85f3db663309b4e251

问题1:GradeCalc 类声明中,逐行写出所有体现"组合"关系的成员声明,并用一句话说明每个被组合对象的功能。

std::string course_name:存储课程名称

std::vector<int> grades:存储学生课程成绩

std::array<int, 5> counts:存储各分数段学生人数

std::array<double, 5> rates:存储各分数段人数占比

问题2:如在 test 模块中这样使用,是否合法?如不合法,解释原因。

GradeCalc c("OOP");

c.input(5);

c.push_back(97); // 合法吗?

不合法。push_back()是vector的成员函数,而grades是GradeCalc的私有成员,类外部无法直接访问调用。

问题3:当前设计方案中, compute 在 info 模块中调用:

(1)连续打印3次统计信息, compute 会被调用几次?标记 is_dirty 起到什么作用?

1 次。is_dirty标记成绩数据是否变更,未变更则重复打印时不重复调用compute,提升效率。

(2)如新增 update_grade(index, new_grade) ,这种设计需要更改 compute 调用位置吗?简洁说明理由。

不需要。新增update_grade时只需修改is_dirty为true,info调用时会自动触发compute,无需改调用位置。

问题4:要增加"中位数"统计,不新增数据成员怎么做?在哪个函数里加?写出伪代码。

在GradeCalc中新增middle()方法,在info()中调用输出,不新增数据成员。

1 double GradeCalc::middle() {
2     if (grades.empty()) return 0;
3     std::vector<int> temp = grades;
4     std::sort(temp.begin(), temp.end());
5     int n = temp.size();
6     return n % 2 ? temp[n/2] : (temp[n/2-1] + temp[n/2])/2.0;
7 }
8 // info()中添加:
9 std::cout << "中位数:\t" << std::fixed << std::setprecision(2) << middle() << std::endl;
View Code

问题5:GradeCalc 和 compute 中都包含代码: counts.fill(0); rates.fill(0); compute 中能否去掉这两行?如去掉,在哪种使用场景下会引发统计错误?

不能去掉。若去掉,多次调用compute(如成绩更新后重复统计)时,counts和rates会在原有结果上累加,导致统计数据错误。

问题6:input 模块中代码 grades.reserve(n); 如果去掉:

(1)对程序功能有影响吗?(去掉重新编译、运行,观察功能是否受影响)

无影响,程序可正常编译运行。

(2)对性能有影响吗?如有影响,用一句话陈述具体影响。

有影响,vector 会频繁重新分配内存并拷贝数据,导致大数据量输入时性能下降。

 

二、实验任务2

源代码task2

  1 #include <algorithm>
  2 #include <array>
  3 #include <cstdlib>
  4 #include <iomanip>
  5 #include <iostream>
  6 #include <numeric>
  7 #include <string>
  8 #include <vector>
  9 #include "GradeCalc.hpp"
 10 
 11 
 12 GradeCalc::GradeCalc(const std::string &cname): course_name{cname}, is_dirty{true}{
 13     counts.fill(0);
 14     rates.fill(0);
 15 }   
 16 
 17 void GradeCalc::input(int n) {
 18     if(n < 0) {
 19         std::cerr << "无效输入! 人数不能为负数\n";
 20         return;
 21     }
 22 
 23     this->reserve(n);
 24 
 25     int grade;
 26 
 27     for(int i = 0; i < n;) {
 28         std::cin >> grade;
 29         if(grade < 0 || grade > 100) {
 30             std::cerr << "无效输入! 分数须在[0,100]\n";
 31             continue;
 32         }
 33 
 34         this->push_back(grade);
 35         ++i;
 36     } 
 37 
 38     is_dirty = true;
 39 }  
 40 
 41 void GradeCalc::output() const {
 42     for(auto grade: *this)
 43         std::cout << grade << ' ';
 44     std::cout << std::endl;
 45 } 
 46 
 47 void GradeCalc::sort(bool ascending) {
 48     if(ascending)
 49         std::sort(this->begin(), this->end());
 50     else
 51         std::sort(this->begin(), this->end(), std::greater<int>());
 52 }  
 53 
 54 int GradeCalc::min() const {
 55     if(this->empty())
 56         return -1;
 57 
 58     return *std::min_element(this->begin(), this->end());
 59 }  
 60 
 61 int GradeCalc::max() const {
 62     if(this->empty())
 63         return -1;
 64 
 65     return *std::max_element(this->begin(), this->end());
 66 }    
 67 
 68 double GradeCalc::average() const {
 69     if(this->empty())
 70         return 0.0;
 71 
 72     double avg = std::accumulate(this->begin(), this->end(), 0.0) / this->size();
 73     return avg;
 74 }   
 75 
 76 void GradeCalc::info() {
 77     if(is_dirty) 
 78         compute();
 79 
 80     std::cout << "课程名称:\t" << course_name << std::endl;
 81     std::cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() << std::endl;
 82     std::cout << "最高分:\t" << max() << std::endl;
 83     std::cout << "最低分:\t" << min() << std::endl;
 84 
 85     const std::array<std::string, 5> grade_range{"[0, 60) ", 
 86                                            "[60, 70)", 
 87                                            "[70, 80)",
 88                                            "[80, 90)", 
 89                                            "[90, 100]"};
 90     
 91     for(int i = static_cast<int>(grade_range.size())-1; i >= 0; --i)
 92         std::cout << grade_range[i] << "\t: " << counts[i] << "人\t"
 93                   << std::fixed << std::setprecision(2) << rates[i]*100 << "%\n";
 94 }
 95 
 96 void GradeCalc::compute() {
 97     if(this->empty())
 98         return;
 99     
100     counts.fill(0);
101     rates.fill(0);
102 
103     // 统计各分数段人数
104     for(int grade: *this) {
105         if(grade < 60)
106             ++counts[0];        // [0, 60)
107         else if (grade < 70)
108             ++counts[1];        // [60, 70)
109         else if (grade < 80)
110             ++counts[2];        // [70, 80)
111         else if (grade < 90)
112             ++counts[3];        // [80, 90)
113         else
114             ++counts[4];        // [90, 100]
115     }
116 
117     // 统计各分数段比例
118     for(size_t i = 0; i < rates.size(); ++i)
119         rates[i] = counts[i] * 1.0 / this->size();
120     
121     is_dirty = false;
122 }
GradeCalc.cpp
 1 #pragma once
 2 
 3 #include <array>
 4 #include <string>
 5 #include <vector>
 6 
 7 class GradeCalc: private std::vector<int> {
 8 public:
 9     GradeCalc(const std::string &cname);      
10     void input(int n);                        // 录入n个成绩
11     void output() const;                      // 输出成绩
12     void sort(bool ascending = false);        // 排序 (默认降序)
13     int min() const;                          // 返回最低分
14     int max() const;                          // 返回最高分
15     double average() const;                   // 返回平均分
16     void info();                              // 输出成绩统计信息 
17 
18 private:
19     void compute();               // 计算成绩统计信息
20 
21 private:
22     std::string course_name;     // 课程名
23     std::array<int, 5> counts;   // 保存各分数段人数([0, 60), [60, 70), [70, 80), [80, 90), [90, 100]
24     std::array<double, 5> rates; // 保存各分数段占比
25     bool is_dirty;      // 脏标记,记录是否成绩信息有变更
26 };
GradeCalc.hpp
 1 #include <iostream>
 2 #include <string>
 3 #include "GradeCalc.hpp"
 4 
 5 void test() {
 6     GradeCalc c1("OOP");
 7 
 8     std::cout << "录入成绩:\n";
 9     c1.input(5);
10 
11     std::cout << "输出成绩:\n";
12     c1.output();
13 
14     std::cout << "排序后成绩:\n";
15     c1.sort(); c1.output();
16 
17     std::cout << "*************成绩统计信息*************\n";
18     c1.info();
19 
20 }
21 
22 int main() {
23     test();
24 }
task2.cpp

运行结果截图

b285f0baad7c227ef2ed6161ab91c29a

问题1:写出 GradeCalc 类声明体现"继承"关系的完整代码行。

class GradeCalc : private std::vector<int>

问题2:当前继承方式下,基类 vector<int> 的接口会自动成为 GradeCalc 的接口吗?如在 test 模块中这样用,能否编译通过?用一句话解释原因。

GradeCalc c("OOP");

c.input(5);

c.push_back(97); // 合法吗?

基类vector<int>的接口不会自动成为GradeCalc的接口,编译不能通过。原因:private 继承会将基类接口设为私有,类外部无法直接调用push_back等基类方法。

问题3: 对比继承方式与组合方式内部实现数据访问的一行典型代码。说明两种方式下的封装差异带来的数据访问接口差异。

// 组合方式

for(auto grade: grades) // 通过什么接口访问数据

// 略

// 继承方式

for(int grade: *this) // 通过什么接口访问数据

// 略

组合方式:for(auto grade: grades),通过类的私有成员变量grades(组合的容器对象)访问数据;

继承方式:for(int grade: *this),通过派生类自身(this指针指向的基类实例)的迭代器接口访问数据。

封装差异:组合方式封装性更强,数据通过成员变量间接访问,外部无法直接操作;继承方式封装性较弱,派生类可直接复用基类接口,易暴露不必要的操作。

问题4:你认为组合方案和继承方案,哪个更适合成绩计算这个问题场景?简洁陈述你的结论和理由。

组合方案更适合。理由:1.符合 “成绩统计类包含成绩容器” 的逻辑关系,而非 “成绩统计类是容器” 的继承关系;2.封装性更强,避免暴露vector的无关接口(如push_back),数据安全性更高;3.扩展性更好,后期更换存储容器时只需修改内部成员,不影响外部调用。

 

三、实验任务3

源代码task3

 1 #include <algorithm>
 2 #include <cctype>
 3 #include <iostream>
 4 #include <string>
 5 
 6 #include "Graph.hpp"
 7 
 8 // Circle类实现
 9 void Circle::draw()     { std::cout << "draw a circle...\n"; }
10 
11 // Triangle类实现
12 void Triangle::draw()   { std::cout << "draw a triangle...\n"; }
13 
14 // Rectangle类实现
15 void Rectangle::draw()  { std::cout << "draw a rectangle...\n"; }
16 
17 // Canvas类实现
18 void Canvas::add(const std::string& type) {
19     Graph* g = make_graph(type);
20     if (g) 
21         graphs.push_back(g);
22 }
23 
24 void Canvas::paint() const {
25     for (Graph* g : graphs) 
26         g->draw();   
27 }
28 
29 Canvas::~Canvas() {
30     for (Graph* g : graphs) 
31         delete g;
32 }
33 
34 // 工具函数实现
35 // 字符串 → 枚举转换
36 GraphType str_to_GraphType(const std::string& s) {
37     std::string t = s;
38     std::transform(s.begin(), s.end(), t.begin(),
39                    [](unsigned char c) { return std::tolower(c);});
40 
41     if (t == "circle")   
42         return GraphType::circle;
43 
44     if (t == "triangle") 
45         return GraphType::triangle;
46 
47     if (t == "rectangle")
48         return GraphType::rectangle;
49 
50     return GraphType::circle;   // 缺省返回
51 }
52 
53 // 创建图形,返回堆对象指针
54 Graph* make_graph(const std::string& type) {
55     switch (str_to_GraphType(type)) {
56     case GraphType::circle:     return new Circle;
57     case GraphType::triangle:   return new Triangle;
58     case GraphType::rectangle:  return new Rectangle;
59     default: return nullptr;
60     }
61 }
Graph.cpp
 1 #pragma once
 2 
 3 #include <string>
 4 #include <vector>
 5 
 6 enum class GraphType {circle, triangle, rectangle};
 7 
 8 // Graph类定义
 9 class Graph {
10 public:
11     virtual void draw() {}
12     virtual ~Graph() = default;
13 };
14 
15 // Circle类声明
16 class Circle : public Graph {
17 public:
18     void draw();
19 };
20 
21 // Triangle类声明
22 class Triangle : public Graph {
23 public:
24     void draw();
25 };
26 
27 // Rectangle类声明
28 class Rectangle : public Graph {
29 public:
30     void draw();
31 };
32 
33 // Canvas类声明
34 class Canvas {
35 public:
36     void add(const std::string& type);   // 根据字符串添加图形
37     void paint() const;                  // 使用统一接口绘制所有图形
38     ~Canvas();                           // 手动释放资源
39 
40 private:
41     std::vector<Graph*> graphs;          
42 };
43 
44 // 4. 工具函数
45 GraphType str_to_GraphType(const std::string& s);  // 字符串转枚举类型
46 Graph* make_graph(const std::string& type);  // 创建图形,返回堆对象指针
Graph.hpp
 1 #include <string>
 2 #include "Graph.hpp"
 3 
 4 void test() {
 5     Canvas canvas;
 6 
 7     canvas.add("circle");
 8     canvas.add("triangle");
 9     canvas.add("rectangle");
10     canvas.paint();
11 }
12 
13 int main() {
14     test();
15 }
demo3.cpp

运行结果截图

f7ac130423c5f226f03ac3c69cdbea7a

问题1:

(1)写出Graph.hpp中体现"组合"关系的成员声明代码行,并用一句话说明被组合对象的功能。 

Canvas类中:std::vector<Graph*> graphs;,功能是存储指向各类图形对象(Graph 派生类实例)的指针,实现图形集合管理。

(2)写出Graph.hpp中体现"继承"关系的类声明代码行。

class Circle : public Graph;

class Triangle : public Graph;

class Rectangle : public Graph;

问题2:

(1) Graph 中的 draw 若未声明成虚函数, Canvas::paint() 中 g->draw() 运行结果会有何不同?

所有g->draw()都会调用基类Graph的draw函数,无法触发派生类(圆形、三角形等)的重写实现,丧失多态特性。

(2)若 Canvas 类 std::vector<Graph*> 改成 std::vector<Graph> ,会出现什么问题?

会发生 “对象切片”,存储时仅拷贝派生类的基类部分,派生类特有成员和重写接口丢失,调用draw时始终执行基类逻辑,且无法体现多态。

(3)若 ~Graph() 未声明成虚函数,会带来什么问题?

析构基类指针指向的派生类对象时,仅调用基类析构函数,派生类中堆内存资源无法释放,导致内存泄漏。

问题3: 若要新增星形 Star ,需在哪些文件做哪些改动?逐一列出。

Graph.hpp:1.新增Star类继承Graph,声明draw纯虚函数实现;2.在GraphType枚举中添加star枚举值。

Graph.cpp:1.实现Star::draw()函数(输出绘图逻辑);2.在str_to_GraphType函数中添加分支:若输入字符串为 "star",返回GraphType::star;3.在make_graph函数中添加case GraphType::star,返回new Star()。

task3.cpp:在测试代码中添加canvas.add("star"),将星形图形加入画布。

问题4:观察 make_graph 函数和 Canvas 析构函数:

(1) make_graph 返回的对象在什么地方被释放?

make_graph返回的堆上图形对象,在Canvas类的析构函数中被释放(通过遍历graphs容器,对每个指针调用delete)。

(2)使用原始指针管理内存有何利弊?

利:使用简单、直观,无需依赖额外工具(如智能指针),学习成本低;

弊:需手动管理内存释放,易因遗漏delete、重复释放或野指针导致内存泄漏,安全性较低。

 

四、实验任务4

1.问题场景描述
设计一个电子毛绒玩具管理系统,用于统一管理具有不同特异功能的智能毛绒玩具。系统需要支持多种功能类型的玩具(如发光、对话、跳舞等),并提供统一接口展示所有玩具的基础信息和特异功能。
2.各类之间的关系(继承、组合等)及设计理由
继承关系:Toy 作为抽象基类,定义玩具通用属性和接口 GlowingToy、TalkingToy、DancingToy 继承自 Toy,实现具体功能
组合关系:ToyFactory 包含 vector<Toy*>,管理玩具集合 体现"工厂包含多个玩具"的现实关系
多态应用:通过虚函数 showSpecialFunction() 实现统一接口调用不同功能
3.源代码
 1 #ifndef TOY_SYSTEM_HPP
 2 #define TOY_SYSTEM_HPP
 3 
 4 #include <string>
 5 #include <vector>
 6 #include <iostream>
 7 #include <iomanip>
 8 
 9 class Toy {
10 protected:
11     std::string name;
12     std::string type;
13     double price;
14     std::string manufacturer;
15     int batteryLevel;
16 
17 public:
18     Toy(std::string name, std::string type, double price, 
19         std::string manufacturer, int batteryLevel);
20     
21     void showBasicInfo() const;
22     virtual void showSpecialFunction() const = 0;
23     virtual ~Toy() {}
24 };
25 
26 class GlowingToy : public Toy {
27 private:
28     std::string lightColor;
29     std::string lightMode;
30 
31 public:
32     GlowingToy(std::string name, double price, std::string manufacturer, 
33                int batteryLevel, std::string lightColor, std::string lightMode);
34     void showSpecialFunction() const override;
35 };
36 
37 class TalkingToy : public Toy {
38 private:
39     std::string language;
40     int phraseCount;
41 
42 public:
43     TalkingToy(std::string name, double price, std::string manufacturer, 
44                int batteryLevel, std::string language, int phraseCount);
45     void showSpecialFunction() const override;
46 };
47 
48 class DancingToy : public Toy {
49 private:
50     int danceMoves;
51     bool hasMusic;
52 
53 public:
54     DancingToy(std::string name, double price, std::string manufacturer, 
55                int batteryLevel, int danceMoves, bool hasMusic);
56     void showSpecialFunction() const override;
57 };
58 
59 class ToyFactory {
60 private:
61     std::string factoryName;
62     std::vector<Toy*> toyList;
63 
64 public:
65     ToyFactory(std::string name);
66     void addToy(Toy* toy);
67     void displayAllToys() const;
68     ~ToyFactory();
69 };
70 
71 #endif
toy_system.hpp
 1 #include "toy_system.hpp"
 2 
 3 Toy::Toy(std::string name, std::string type, double price, 
 4          std::string manufacturer, int batteryLevel)
 5     : name(name), type(type), price(price), 
 6       manufacturer(manufacturer), batteryLevel(batteryLevel) {}
 7 
 8 void Toy::showBasicInfo() const {
 9     std::cout << "【基本信息】" << std::endl;
10     std::cout << "玩具名称: " << name << std::endl;
11     std::cout << "玩具类型: " << type << std::endl;
12     std::cout << "价格: ¥" << std::fixed << std::setprecision(2) << price << std::endl;
13     std::cout << "生产厂家: " << manufacturer << std::endl;
14     std::cout << "当前电量: " << batteryLevel << "%" << std::endl;
15 }
16 
17 GlowingToy::GlowingToy(std::string name, double price, std::string manufacturer, 
18                        int batteryLevel, std::string lightColor, std::string lightMode)
19     : Toy(name, "发光毛绒玩具", price, manufacturer, batteryLevel), 
20       lightColor(lightColor), lightMode(lightMode) {}
21 
22 void GlowingToy::showSpecialFunction() const {
23     std::cout << "【特异功能】" << std::endl;
24     std::cout << "功能类型: 七彩发光" << std::endl;
25     std::cout << "发光颜色: " << lightColor << std::endl;
26     std::cout << "发光模式: " << lightMode << std::endl;
27 }
28 
29 TalkingToy::TalkingToy(std::string name, double price, std::string manufacturer, 
30                        int batteryLevel, std::string language, int phraseCount)
31     : Toy(name, "语音对话玩具", price, manufacturer, batteryLevel), 
32       language(language), phraseCount(phraseCount) {}
33 
34 void TalkingToy::showSpecialFunction() const {
35     std::cout << "【特异功能】" << std::endl;
36     std::cout << "功能类型: 智能对话" << std::endl;
37     std::cout << "支持语言: " << language << std::endl;
38     std::cout << "内置短语: " << phraseCount << "" << std::endl;
39 }
40 
41 DancingToy::DancingToy(std::string name, double price, std::string manufacturer, 
42                        int batteryLevel, int danceMoves, bool hasMusic)
43     : Toy(name, "舞蹈玩具", price, manufacturer, batteryLevel), 
44       danceMoves(danceMoves), hasMusic(hasMusic) {}
45 
46 void DancingToy::showSpecialFunction() const {
47     std::cout << "【特异功能】" << std::endl;
48     std::cout << "功能类型: 欢乐舞蹈" << std::endl;
49     std::cout << "舞蹈动作: " << danceMoves << "" << std::endl;
50     std::cout << "音乐播放: " << (hasMusic ? "支持" : "不支持") << std::endl;
51 }
52 
53 ToyFactory::ToyFactory(std::string name) : factoryName(name) {}
54 
55 void ToyFactory::addToy(Toy* toy) {
56     if (toy != nullptr) {
57         toyList.push_back(toy);
58     }
59 }
60 
61 void ToyFactory::displayAllToys() const {
62     std::cout << "========== " << factoryName << " 玩具展示 ==========" << std::endl;
63     
64     for (size_t i = 0; i < toyList.size(); ++i) {
65         std::cout << "\n第 " << (i + 1) << " 款玩具:" << std::endl;
66         toyList[i]->showBasicInfo();
67         toyList[i]->showSpecialFunction();
68         std::cout << "-----------------------------------" << std::endl;
69     }
70 }
71 
72 ToyFactory::~ToyFactory() {
73     for (Toy* toy : toyList) {
74         delete toy;
75     }
76     toyList.clear();
77 }
toy_system.cpp
 1 #include "toy_system.hpp"
 2 
 3 int main() {
 4     ToyFactory factory("智能玩具厂");
 5     
 6     Toy* bear = new GlowingToy("闪光熊", 88.0, "小熊公司", 80, "七彩", "呼吸灯");
 7     Toy* rabbit = new TalkingToy("对话兔", 120.0, "乐乐厂", 65, "中英文", 200);
 8     Toy* panda = new DancingToy("舞蹈熊猫", 150.0, "国宝玩具", 90, 5, true);
 9     
10     factory.addToy(bear);
11     factory.addToy(rabbit);
12     factory.addToy(panda);
13     
14     factory.displayAllToys();
15     
16     return 0;
17 }
demo4.cpp

运行测试截图

9c3427c5552559b3d00ab89474b077e2

设计总结:

系统通过继承实现多态,统一管理不同功能类型的玩具。ToyFactory类组合管理玩具集合,提供批量展示功能。虚函数机制确保统一接口调用不同特异功能,具有良好的扩展性。

 

实验总结:

通过本次实验,我深入理解了组合与继承在面向对象设计中的应用。继承实现了多态特性,允许通过统一接口调用不同功能;组合则建立了对象间的层次关系,提升了系统的灵活性。

虚函数的运用是本次实验的关键,它实现了"一个接口,多种实现"的设计理念,为系统扩展提供了良好基础。这次实践让我掌握了在不同场景下选择合适设计模式的方法。

posted @ 2025-11-28 11:10  htsjubbymjeymsy  阅读(0)  评论(0)    收藏  举报