实验4 组合与继承

实验任务一:

源代码:

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

运行结果截图:

image

 回答问题:

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

  std::vector<int> grades;:存储课程的成绩数据,便于后续的功能实现。

  std::array<int, 5> counts;:分别存储 5 个分数段的人数,便于快速展示分数分布。

  std::array<double, 5> rates;:存储 5 个分数段的人数占比,辅助统计信息输出。

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

  GradeCalc c("OOP");

  c.inupt(5);

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

   不合法。原因:vector<int> grades是 GradeCalc 类的私有成员,组合关系下无法直接调用vector的接口 push_back。

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

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

  1次;is_dirty作用:记录成绩信息是否变更。

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

  不需要;理由:只需在函数内设置is_dirty = true,info函数会自动检测脏标记并执行 compute函数。

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

  

  double GradeCalc::median() const{
  if (grades.empty()) return 0.0;

  std::sort(grades.begin(), grades.end());
  int size = grades.size();
  if (size % 2 == 1) {
  return grades[size / 2];
  }
  else {
  return (grades[size / 2 - 1] + grades[size / 2]) / 2.0;
  }
}

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

  不能;如果去掉,会造成重复统计。counts 和 rates 会保留上一次的统计结果,导致重复统计,出现结果错误。当录入成绩后调用 info函数,修改成绩后再次调用 info函数,此时 counts 不为零,会在原有结果上叠加新统计值。

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

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

  无影响。

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

  有;当n足够大时,grades 会因容量不足多次内存重新分配和数据拷贝,导致录入效率下降。

 实验任务二:

源代码:

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

运行结果截图:

image

 回答问题:

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

  class GradeCalc: private std::vector    //继承标准库中的接口vector
问题2:接口暴露理解 当前继承方式下,基类vector的接口会自动成为GradeCalc的接口吗? 如在test模块中这样用,能否编译通过?用一句话解释原因。

  GradeCalc c("OOP");

  c.input(5);

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

 

  不会成为GradeCalc的接口,编译不通过;原因:GradeCalc 采用私有继承 vector<int>,vector<int>中的接口(如push_back等)会被隐藏,外部无法直接调用。

问题3:数据访问差异

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

  // 组合方式 for(auto grade: grades)  //通过私有成员变量直接访问数据。

  // 继承方式 for(int grade: *this)     //通过 this 指针访问数据。

差异:组合是 “has-a” 关系,数据访问受类接口限制;继承是 “is-a” 关系,子类可直接访问基类数据。综合来看,组合方式封装性更强。

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

  组合更合适;理由:从数据访问差异等方面来看,明显组合的封装性更好,存储的数据更为安全。且组合更具有灵活性,增添相关功能时更方便,而继承局限于“is-a”的关系。

实验任务三:

源代码:

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

运行结果截图:

image

问题1:对象关系识别

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

   std::vector<Graph*> graphs;     用vector容器存储指向Graph类型的指针,便于实行增删改查等操作。

 

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

  class Circle : public Graph

  class Triangle : public Graph

  class Rectangle : public Graph

 

问题2:多态机制观察

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

  所有调用都会执行基类 Graph 的 draw () 函数(无输出或默认输出),失去多态特性,无法调用子类的具体绘制实现。

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

   会发生“对象切片”,即:对象存储到 vector<Graph>时,仅保留基类部分数据,子类特有成员丢失,调用 draw () 时也仅会执行基类逻辑。

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

   内存会泄漏;删除 Graph * 指针时,仅调用基类析构函数,子类对象所占用的内存无法释放(子类析构函数不会执行)。

 

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

Graph.hpp:

   增加GraphType枚举: enum class GraphType {circle, triangle, rectangle, star}

   新增Star类:class Star : public Graph { public: void draw() ; }

Graph.cpp:

   void Star::draw(){ std::cout << "draw a star...\n";} 

   定义 str_to_GraphType 函数:if (t == "star") return GraphType::star;

   定义 make_graph 函数:case GraphType::star: return new Star;

 

问题4:资源管理 观察make_graph函数和Canvas析构函数:

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

   make_graph 返回的对象在 Canvas 类的析构函数中被释放。

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

     利:灵活性高,可动态管理不同类型的对象,直接控制对象的创建和释放时机。

  弊:可能出现内存泄漏的现象,以及出现“野指针”,手动管理成本高。

 

实验任务四:

问题描述:设计一套电子毛绒玩具管理系统,支持多种玩具(如bear、rabbit、bird等),通过玩具工厂类统一管理所有玩具,提供展示所有玩具信息,通过价格排序以及通过产地查找玩具的接口,支持添加新玩具。

对象关系:

  继承关系:Toy(基类)→ BearToy(子类)、RabbitToy(子类)、BirdToy(子类)。理由:所有玩具都具有基础属性(名称、类型、产地、价格)和特有属性(特异功能),子类通过继承基类获得基础属性和接口,并实现特异功能实现。

  组合关系:ToyFactory(工厂类)→ std::vector<Toy*>(玩具)。理由:工厂 “包含” 多个玩具,便于统一集中管理玩具,同时vector还提供多种接口便于使用,可以有效减少代码量,让代码更为简洁。也符合 “has-a” 关系。

 

源代码:

 1 #pragma once
 2 #include<vector>
 3 #include<string>
 4 
 5 using std::string;
 6 using std::vector;
 7 
 8 //enum class ToyType{ bear,rabbit,bird};  
 9 class Toy {
10 public:
11     Toy(const string& name_, const string& type_,const string& source_, double price_);
12 
13     virtual ~Toy() = default;
14     virtual void Info() const;                              // 展示玩具基础信息
15     virtual bool is_money_enough(double money) const;       //判断钱是否够买
16     virtual void show_specialfunction() const=0;            //展示特异功能
17     virtual string& get_source()  ;                       //得到产地
18     virtual string& get_name();                           //得到名称
19     virtual double get_price();                           //得到价格
20 private:
21     string name;            //玩具名称
22     string type;            //玩具类型
23     string source;          //玩具产地
24 
25     double price;           //玩具价格
26 
27 };
28 
29 class BearToy :public Toy {
30 public:
31     BearToy(const string& name_, const string& type_, const string& source_, double price_ ,const string& specialfunction_);
32     void show_specialfunction() const;      //展示特异功能
33 private:
34     string specialfunction;    //
35 };
36 
37 class RabbitToy :public Toy {
38 public:
39     RabbitToy(const string& name_, const string& type_, const string& source_, double price_, const string& specialfunction_);
40     void show_specialfunction() const;      //展示特异功能
41 private:
42     string specialfunction;  //
43 };
44 
45 class BirdToy :public Toy {
46 public:
47     BirdToy(const string& name_, const string& type_, const string& source_, double price_, const string& specialfunction_);
48     void show_specialfunction() const;      //展示特异功能
49 private:
50     string specialfunction;
51 };
52 
53 class ToyFactory {
54 public:
55     ~ToyFactory();
56     void add_toy(Toy* toy); // 添加玩具
57     void display() const; // 展示所有玩具信
58     void find_toy(const string source) const ;   //由产地溯源
59     void sort_price() ;                    //价格升序排列
60 private:
61     vector<Toy*> toys; // 存储所有玩具
62 };
Toy.hpp
 1 #pragma once
 2 #include<iostream>
 3 #include<string>
 4 #include<vector>
 5 #include<algorithm>
 6 #include"Toy.hpp"
 7 using namespace std;
 8 ;
 9 
10 Toy::Toy(const string& name_, const string& type_, const string& source_, double price_) :
11     name{ name_ }, type{ type_ }, source{ source_ }, price{ price_ } {}
12 
13 void Toy::Info()const {
14     cout << "玩具名称:" << name << '\n'
15         << "玩具类型:" << type << '\n'
16         << "玩具产地:" << source << '\n'
17         << "玩具价格:" << price << "元\n";
18 }
19 
20 bool Toy::is_money_enough(double money)const{
21     return money >= price;
22 }
23 string& Toy::get_source() {
24     return source;
25 }
26 string& Toy::get_name() {
27     return name;
28 }
29 double Toy::get_price() {
30     return price;
31 }
32 BearToy::BearToy(const string& name_, const string& type_, const string& source_, double price_, const string& specialfunction_):
33     Toy(name_,type_,source_,price_),specialfunction{specialfunction_}{ }
34 void BearToy::show_specialfunction() const {
35     cout << "*特异功能:" << specialfunction<<'\n';
36 }
37 RabbitToy::RabbitToy(const string& name_, const string& type_, const string& source_, double price_, const string& specialfunction_) :
38     Toy(name_, type_, source_, price_), specialfunction{ specialfunction_ } {
39 }
40 void RabbitToy::show_specialfunction() const {
41     cout << "*特异功能:" << specialfunction << '\n';
42 }
43 
44 BirdToy::BirdToy(const string& name_, const string& type_, const string& source_, double price_, const string& specialfunction_) :
45     Toy(name_, type_, source_, price_), specialfunction{ specialfunction_ } {
46 }
47 void BirdToy::show_specialfunction() const {
48     cout << "*特异功能:" << specialfunction << '\n';
49 }
50 
51 ToyFactory::~ToyFactory() {
52     for (Toy* toy : toys) {
53         delete toy;
54     }
55 }
56 
57 void ToyFactory::add_toy(Toy* toy){
58     if (toy) {
59         toys.push_back(toy);
60     }
61 }
62 void ToyFactory::display() const{
63     cout << "---------------玩具工厂所有玩具信息 -----------------\n";
64     if (toys.empty()) {
65             cout << "工厂内没有玩具。\n";
66             return;
67     }
68     for (auto t : toys) {
69         t->Info();
70         t->show_specialfunction();
71         cout << '\n';
72     }
73     cout << "-----------------------------------------------------\n";
74 
75 }
76 void ToyFactory::find_toy(const string place) const{
77     string res;
78     int flag=0;
79     if (toys.empty()) {
80         cout<<"工厂为空,无法查找\n";
81         return ;
82     }
83     for (auto t : toys) {
84         if (t->get_source() == place) {
85             res += t->get_name();
86             res += '\n';
87             flag = 1;
88         }
89     }
90     if (flag == 0) cout << "没有产自"<<place<<"的玩具\n";
91     else cout << "产自" << place << "的有:\n" << res;
92 }
93 void ToyFactory::sort_price()  {
94     sort(toys.begin(), toys.end(), [](auto a, auto b) {return a->get_price() < b->get_price();});
95 }
Toy.cpp
 1 #include "Toy.hpp"
 2 #include <iostream>
 3 
 4  ToyFactory factory;     // 工厂类
 5 void test1() {              // 测试函数
 6    
 7     // 调用工厂接口添加玩具
 8     factory.add_toy(new BearToy("毛绒小熊", "经典","南京", 199.9,"当吉祥物"));
 9     factory.add_toy(new RabbitToy("电动兔", "复古","南京", 69.9, "可以跑,但需要充电"));
10     factory.add_toy(new BirdToy("智能鸟", "智能","北京", 99.9, "像人一样说话"));
11 
12     factory.display();          // 调用工厂接口展示所有玩具
13 
14     factory.find_toy("南京");
15     factory.sort_price();
16     std::cout << "\n排序后:\n";
17     factory.display();
18 }
19 
20 
21 int main() {
22     test1(); 
23     return 0;
24 }
demo4.cpp

 

运行结果截图:

image

 

posted @ 2025-11-30 12:14  pithia  阅读(0)  评论(0)    收藏  举报