实验4 组合与继承

news/2025/11/26 18:33:02/文章来源:https://www.cnblogs.com/yycnuist/p/19271145

实验任务1

程序源代码如下:

GradeCalc.hpp

 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);                        
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::vector<int> grades;     
24     std::array<int, 5> counts;      
25     std::array<double, 5> rates;    
26     bool is_dirty;      
27 };

GradeCalc.cpp

  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     for (auto grade : grades) {
107         if (grade < 60)
108             ++counts[0];        
109         else if (grade < 70)
110             ++counts[1];        
111         else if (grade < 80)
112             ++counts[2];      
113         else if (grade < 90)
114             ++counts[3];       
115         else
116             ++counts[4];        
117     }
118 
119     for (size_t i = 0; i < rates.size(); ++i)
120         rates[i] = counts[i] * 1.0 / grades.size();
121 
122     is_dirty = false;  
123 }

task1.cpp

 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 }

程序运行结果如下所示:

2f703b2b44d60d484847125dc6707720

问题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容器的函数,对象c中的vector对象grades是私有成员,类外部不可以直接访问,故不合法
 
问题3:当前设计方案中, compute 在 info 模块中调用:
(1)连续打印3次统计信息, compute 会被调用几次?标记 is_dirty 起到什么作用?
compute只会被调用1次,因为调用一次之后,is_dirty被赋值为false,接下来再次进行信息打印时,compute不会被调用
is_dirty作用是标记当前状态下成绩是否已经被统计过,若当前状态下成绩已被统计过,接下来打印信息时不重复统计,若成绩信息有变更,is_dirty值改变,表示当前状态未被统计过,就需要重新对成绩信息进行统计
(2)如新增 update_grade(index, new_grade) ,这种设计需要更改 compute 调用位置吗?简洁说明理由。
不需要,compute是否调用是与is_dirty的值有关的,而非和调用位置有关,只需要在updata_grade中进行修改is_dirty的值,即可实现compute的调用。
 
问题4:要增加"中位数"统计,不新增数据成员怎么做?在哪个函数里加?写出伪代码。
可以在sort函数中加入这个功能,把函数返回值类型改为double,完成排序后
if(grades.size()%2!=0){return grades[grades.size()/2];}
else{return (grades[grades.size()/2-1]+grades[grades.size()/2])/2;}
 
问题5:GradeCalc 和 compute 中都包含代码: counts.fill(0); rates.fill(0); compute 中能否去掉这两行?如去掉,在哪种使用场景下会引发统计错误?
不可以去掉,如果把这两行去掉,相当于失去了这两个统计数组的重置功能,那么当已经进行了一次成绩的统计,要进行第二次成绩统计时,count值会在原来数据基础上进行累加,导致统计结果的错误
 
问题6:input 模块中代码 grades.reserve(n); 如果去掉:
(1)对程序功能有影响吗?(去掉重新编译、运行,观察功能是否受影响)
没有影响,注释此行后,程序依旧可以正常运行。
(2)对性能有影响吗?如有影响,用一句话陈述具体影响。
有影响。若不提前分配好足够的空间,vector容器会不断分配新的内存空间,导致性能降低
 
实验任务2
实验源代码如下:
GradeCalc.hpp
 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);                       
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;   
24     std::array<double, 5> rates;
25     bool is_dirty;      
26 };

GradeCalc.cpp

  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     for (int grade : *this) {
104         if (grade < 60)
105             ++counts[0];        
106         else if (grade < 70)
107             ++counts[1];        
108         else if (grade < 80)
109             ++counts[2];        
110         else if (grade < 90)
111             ++counts[3];        
112         else
113             ++counts[4];        
114     }
115 
116     for (size_t i = 0; i < rates.size(); ++i)
117         rates[i] = counts[i] * 1.0 / this->size();
118 
119     is_dirty = false;
120 }

task2.cpp

 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 }

程序运行结果如下:

a7210b8ba0325c216397e05f99280af6

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

class GradeCalc : private std::vector<int> 

 

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

GradeCalc c("OOP");
c.input(5);
c.push_back(97); // 合法吗?
不会自动成为GradeCalc的接口,因为GradeCalc以private方式继承vector类,其内部接口的访问权限为private,在vector类外部不能直接访问
编译不能通过,在类外部直接访问了访问权限为私有的函数,会产生错误
 
问题3:
对比继承方式与组合方式内部实现数据访问的一行典型代码。说明两种方式下的封装差异带来的数据访问接口差异。
// 组合方式
for(auto grade: grades) // 通过什么接口访问数据
// 略
// 继承方式
for(int grade: *this) // 通过什么接口访问数据
// 略
组合方式中,利用当前类中的成员变量grades访问数据,其数据被封装在组合类中,当前类不能直接访问这些数据,只能通过组合类对象进行访问
继承方式中,利用当前类的成员的this指针直接访问数据,继承后派生类可以访问基类的数据
组合方式封装性更强,需要通过当前类中的成员变量去间接访问数据,继承方式封装性稍弱,可直接通过当前派生类中的this指针去访问基类数据
 
问题4:你认为组合方案和继承方案,哪个更适合成绩计算这个问题场景?简洁陈述你的结论和理由。
 我认为组合更适合这个问题场景
1.组合方式封装性更强,只能通过组合类成员对数据进行访问而不会直接接触数据,安全性更好
2.组合方式更符合现实认知,成绩统计中,应该是需要一个vector类容器作为工具来进行成绩统计,二者是一个包含关系,而非成绩统计继承于vector类
3.组合方式更便于后期的修改,若后期需要更换存储容器,只需要修改组合类成员及其对应的访问方式即可,而继承方式要修改的地方相对较多
 
实验任务3
程序源代码如下:
Graph.hpp
 1 #pragma once
 2 
 3 #include <string>
 4 #include <vector>
 5 
 6 enum class GraphType { circle, triangle, rectangle };
 7 
 8 class Graph {
 9 public:
10     virtual void draw() {}
11     virtual ~Graph() = default;
12 };
13 
14 class Circle : public Graph {
15 public:
16     void draw();
17 };
18 
19 class Triangle : public Graph {
20 public:
21     void draw();
22 };
23 
24 class Rectangle : public Graph {
25 public:
26     void draw();
27 };
28 
29 class Canvas {
30 public:
31     void add(const std::string& type);   
32     void paint() const;                  
33     ~Canvas();                           
34 
35 private:
36     std::vector<Graph*> graphs;
37 };
38 
39 GraphType str_to_GraphType(const std::string& s);  
40 Graph* make_graph(const std::string& type);  

Graph.cpp

 1 #include <algorithm>
 2 #include <cctype>
 3 #include <iostream>
 4 #include <string>
 5 
 6 #include "Graph.hpp"
 7 
 8 void Circle::draw() { std::cout << "draw a circle...\n"; }
 9 
10 void Triangle::draw() { std::cout << "draw a triangle...\n"; }
11 
12 void Rectangle::draw() { std::cout << "draw a rectangle...\n"; }
13 
14 void Canvas::add(const std::string& type) {
15     Graph* g = make_graph(type);
16     if (g)
17         graphs.push_back(g);
18 }
19 
20 void Canvas::paint() const {
21     for (Graph* g : graphs)
22         g->draw();
23 }
24 
25 Canvas::~Canvas() {
26     for (Graph* g : graphs)
27         delete g;
28 }
29 
30 GraphType str_to_GraphType(const std::string& s) {
31     std::string t = s;
32     std::transform(s.begin(), s.end(), t.begin(),
33         [](unsigned char c) { return std::tolower(c); });
34 
35     if (t == "circle")
36         return GraphType::circle;
37 
38     if (t == "triangle")
39         return GraphType::triangle;
40 
41     if (t == "rectangle")
42         return GraphType::rectangle;
43 
44     return GraphType::circle;   
45 }
46 
47 Graph* make_graph(const std::string& type) {
48     switch (str_to_GraphType(type)) {
49     case GraphType::circle:     return new Circle;
50     case GraphType::triangle:   return new Triangle;
51     case GraphType::rectangle:  return new Rectangle;
52     default: return nullptr;
53     }
54 }

task3.cpp

#include <string>
#include "Graph.hpp"void test() {Canvas canvas;canvas.add("circle");canvas.add("triangle");canvas.add("rectangle");canvas.paint();
}int main() {test();
}

程序运行结果截图如下:

1aff72e3d0ceda13e9d58f12db8acbf3

 问题1:

(1)写出Graph.hpp中体现"组合"关系的成员声明代码行,并用一句话说明被组合对象的功能。
std::vector<Graph*> graphs;:用于存储指向图类对象的指针
(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> ,会出现什么问题?
运行时依旧调用Graph基类中的draw函数,既没有输出,因为派生类的实例对象被创建在堆上,当vector存储为实体而非指针时,vector会尝试将派生类实例对象拷贝到vector的Graph元素中,拷贝过程中派生类的函数draw不会被拷贝到其中,所以调用时调用的是基类Graph的draw函数
(3)若 ~Graph() 未声明成虚函数,会带来什么问题?
会导致子类中的堆上创建的成员不能被析构,造成资源泄漏
 
问题3:
若要新增星形 Star ,需在哪些文件做哪些改动?逐一列出。
1.Graph.hpp中创建一个Star类,继承Graph类,并创建draw函数
2.Graph.hpp中的枚举类中加入star
3.Graph.cpp中加入draw函数的实现,并在str_to_GraphType函数中加入star类的返回,在make_graph中加入star类对象在堆上的创建
4.在task3.cpp中加上canvas.add("star")
 
问题4:观察 make_graph 函数和 Canvas 析构函数:
(1) make_graph 返回的对象在什么地方被释放?
在Canvas类的析构函数中,遍历graphs中的指针并调用delete进行释放
(2)使用原始指针管理内存有何利弊?
利:简单易理解,可实现基本的内存分配
弊:需要自行手动对堆上变量进行删除,若遗忘会造成内存的泄露
 
实验任务4
 1.设计场景:有一些电子毛绒玩具,他们有不同的类别,将他们放入玩具工厂中,在玩具工厂中用一个接口实现对所有玩具玩法的调用
2.各类关系:基类Toy,其有派生类SoundingToy,MovingToy,InteractingToy,玩具工厂类ToyFactory,其内部有vector类的实例对象
设计理由:三类电动毛绒玩具虽然具体功能不同,但他们有一部分属性如名字,描述是共同具有的,故继承基类Toy,而玩具工厂类中需要存储各类玩具的容器,故在ToyFactory内部设计vector类实例对象
3.程序源代码如下:
Toy.hpp
 1 #pragma once
 2 
 3 #include <string>
 4 
 5 enum class ToyType { Sounding, Moving, Interacting };
 6 
 7 class Toy {
 8 public:
 9     Toy(const std::string& _name, const std::string& _description,
10         const std::string& _material, ToyType _type, double _price);
11 
12     virtual ~Toy() = default;
13 
14     virtual void execute() = 0;
15     virtual void showInfo() const;
16 
17     std::string getName() const;
18 
19 private:
20     std::string name;
21     std::string description;
22     std::string material;
23     ToyType type;
24     double price;
25 };
26 
27 std::string ToyTypeToString(ToyType type);

MultiToy.hpp

 1 #pragma once
 2 
 3 #include "Toy.hpp"
 4 
 5 class SoundingToy :public Toy{
 6 public:
 7     SoundingToy(const std::string& _name, const std::string& _description,
 8         const std::string& _material, ToyType _type, double _price, const std::string _speaking);
 9 
10     void execute();
11     void showInfo();
12 
13 private:
14     std::string speaking;
15 };
16 
17 class MovingToy :public Toy {
18 public:
19     MovingToy(const std::string& _name, const std::string& _description,
20         const std::string& _material, ToyType _type, double _price, const std::string _moving);
21 
22     void execute();
23     void showInfo();
24 
25 private:
26     std::string moving;
27 };
28 
29 class InteractingToy :public Toy {
30 public:
31     InteractingToy(const std::string& _name, const std::string& _description,
32         const std::string& _material, ToyType _type, double _price, const std::string _interacting);
33 
34     void execute();
35     void showInfo();
36 
37 private:
38     std::string interacting;
39 };

ToyFactory.hpp

#pragma once#include <vector>
#include "Toy.hpp"
#include "MultiToy.hpp"class ToyFactory{
public:ToyFactory() = default;~ToyFactory();void addToy(Toy* toy);void showAllToys();void play();private:std::vector<Toy*> toys;static int count;
};

Toy.cpp

 1 #include "Toy.hpp"
 2 #include <iostream>
 3 
 4 std::string ToyTypeToString(ToyType type) {
 5     switch (type) {
 6     case ToyType::Sounding: return "发声类玩具";
 7     case ToyType::Moving: return "移动类玩具";
 8     case ToyType::Interacting: return "互动类玩具";
 9     }
10 }
11 
12 Toy::Toy(const std::string& _name, const std::string& _description,
13     const std::string& _material, ToyType _type, double _price):
14     name{_name},description{_description},material{_material},type{_type},price{_price}{}
15 
16 void Toy::showInfo() const{
17     std::cout << "玩具名称:" << name << std::endl;
18     std::cout << "玩具描述:" << description << std::endl;
19     std::cout << "玩具材质:" << material << std::endl;
20     std::cout << "玩具种类:" << ToyTypeToString(type) << std::endl;
21     std::cout << "玩具价格:" << price << std::endl;
22 }
23 
24 std::string Toy::getName() const { return name; }

MultiToy.cpp

 1 #include "MultiToy.hpp"
 2 #include <iostream>
 3 
 4 SoundingToy::SoundingToy(const std::string& _name, const std::string& _description,
 5     const std::string& _material, ToyType _type, double _price, const std::string _speaking):
 6     Toy(_name,_description,_material,_type,_price),speaking{_speaking}{}
 7 
 8 void SoundingToy::execute() {
 9     std::cout << getName() << "说话了,它说:" << speaking;
10 }
11 
12 void SoundingToy::showInfo() {
13     Toy::showInfo();
14     std::cout << "它会说:" << speaking;
15 }
16 
17 MovingToy::MovingToy(const std::string& _name, const std::string& _description,
18     const std::string& _material, ToyType _type, double _price, const std::string _moving):
19     Toy(_name, _description, _material, _type, _price), moving{ _moving } {}
20 
21 void MovingToy::execute() {
22     std::cout << getName() << "活动了,它:" << moving;
23 }
24 
25 void MovingToy::showInfo() {
26     Toy::showInfo();
27     std::cout << "它可以:" << moving;
28 }
29 
30 InteractingToy::InteractingToy(const std::string& _name, const std::string& _description,
31     const std::string& _material, ToyType _type, double _price, const std::string _interacting):
32     Toy(_name, _description, _material, _type, _price), interacting{ _interacting } {}
33 
34 void InteractingToy::execute() {
35     std::cout << getName() << "和你互动,它:" << interacting;
36 }
37 
38 void InteractingToy::showInfo() {
39     Toy::showInfo();
40     std::cout << "它的互动方式是:" << interacting;
41 }

ToyFactory.cpp

 1 #include "ToyFactory.hpp"
 2 #include <iostream>
 3 
 4 int ToyFactory::count = 0;
 5 
 6 ToyFactory::~ToyFactory() {
 7     for (auto toy : toys) {
 8         delete toy;
 9     }
10 }
11 
12 void ToyFactory::addToy(Toy* toy) {
13     toys.push_back(toy);
14     count++;
15 }
16 
17 void ToyFactory::showAllToys() {
18     if (toys.empty()) {
19         std::cout << "工厂内目前没有玩具" << std::endl;
20     }
21     else {
22         std::cout << "工厂内目前有" << count << "个玩具" << std::endl;
23         for (auto toy : toys) {
24             toy->showInfo();
25             std::cout << std::endl;
26         }
27     }
28 }
29 
30 void ToyFactory::play() {
31     if (toys.empty()) {
32         std::cout << "目前没有玩具可玩" << std::endl;
33     }
34     else {
35         for (auto toy : toys) {
36             toy->execute();
37             std::cout << std::endl;
38         }
39     }
40 }

task4.cpp

 1 #include <iostream>
 2 #include "Toy.hpp"
 3 #include "MultiToy.hpp"
 4 #include "ToyFactory.hpp"
 5 
 6 int main() {
 7     ToyFactory factory;
 8     factory.showAllToys();
 9     factory.play();
10     std::cout << std::endl;
11 
12     Toy* toy1 = new SoundingToy("旺财", "一只可爱的小狗", "涤纶", ToyType::Sounding, 100.00, "你好呀!");
13     Toy* toy2 = new MovingToy("团子", "一只可爱的小猫", "", ToyType::Moving, 300.00, "快速跑");
14     Toy* toy3 = new InteractingToy("雪球", "一只可爱的兔子", "硅胶", ToyType::Interacting, 200.00, "摸你的头");
15 
16     factory.addToy(toy1);
17     factory.addToy(toy2);
18     factory.addToy(toy3);
19 
20     factory.showAllToys();
21     factory.play();
22 }

4.程序运行结果如下:

ec1d16ba296a428d97904c08a63ef1c6

 

实验总结

通过此次实验,我明白了组合与继承两种设计方式的优势以及两者的区别,更学会了如何在不同的场景下去应用这两种设计模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/977526.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年下半年成都互联网/小程序/抖音推广/知识产权/视频号推广/微信生态公司综合实力Top10推荐指南

摘要 随着移动互联网的快速发展,小程序已成为企业数字化转型的重要工具。2025年下半年,小程序开发行业呈现出更加专业化、细分化的趋势,各类服务商在技术实力、服务质量和创新能力的竞争愈发激烈。本文基于市场调研…

2025 西安口碑好的权威短视频拍摄运营公司推荐 3 家

在短视频流量红利持续爆发的 2025 年,短视频拍摄运营已成为企业品牌传播、产品推广、获客转化的核心引擎。抖音、快手、视频号等平台用户规模突破百亿,短视频以 “直观、高效、互动性强” 的优势,成为企业触达潜在客…

2025年下半年内蒙古通辽/赤峰/鄂尔多斯/包头/乌兰察布/呼伦贝尔/乌海/巴盟/阿拉善内蒙古房屋检测公司全方位挑选指南

摘要 随着内蒙古城镇化进程加速和既有建筑老龄化趋势明显,房屋检测行业在2025年迎来快速发展期。本文基于市场调研和用户反馈,整理出五家值得关注的房屋检测服务机构推荐名单,排名不分先后,每家机构各有特色。本文…

【机器人移动】暴力dfs和层次遍历bfs

暴力,深搜每一种可能,使用 struct vertice{ int x,y; bool operator<(onst vertice& other)const{if(x != other.x)return x < other.x;return y < other.y;} } vertice v={x,y};保存顶点,使用map: ma…

2025年下半年成都互联网、成都小程序、成都抖音推广、成都知识产权 、成都视频号推广、成都微信生态服务商综合推荐指南

随着移动互联网的快速发展,小程序已成为企业数字化转型的重要工具。2025年下半年,小程序开发行业呈现出更加专业化、细分化的趋势,为企业提供了更多元化的解决方案。本文基于行业调研和用户反馈,整理了十家值得关注…

ThingsBoard部件数据结构解析 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

【LVGL】表格部件

引言 仅作笔记使用,无参考价值。 表格部件(lv_table)表格部件相关 api 函数示例程序 void my_gui(void) {lv_obj_t *table = lv_table_create(lv_scr_act());/* 设置三行三列 */lv_table_set_row_cnt(table, 3);lv_…

【前端从0到1实战】第9篇:构建“无限滚动列表” (Infinite Scroll)

【前端从0到1实战】第9篇:构建“无限滚动列表” (Infinite Scroll) 欢迎来到本系列的第9篇。在上一篇中,我们通过拖拽看板掌握了复杂的鼠标交互。今天,我们将关注“浏览体验”的核心——无限滚动。 传统的“分页”按…

2025液冷超充厂家推荐榜:全液冷/浸没式液冷/大功率/电动汽车/新能源车/超充源头厂家,中碳创新引领技术革命,快速补能成新标杆

随着新能源汽车保有量的持续攀升,补能效率已成为制约行业发展的核心痛点。液冷超充技术凭借高功率输出、高效散热及设备长寿命等优势,成为破解充电焦虑的关键方案。2025年,液冷超充领域技术迭代加速,一批具备核心竞…

2025 西安网站建设公司推荐 3 家口碑好的网站制作公司

在数字化转型纵深推进的 2025 年,网站建设已成为企业品牌传播、业务转化的核心载体,西安作为西北数字化产业枢纽,网站制作、网页设计需求持续攀升。企业选择服务商时,“资质合规性、案例适配性、服务差异化、售后保…

2025济南画室培训推荐榜:山东济南艺考画室/美术艺考培训/画室机构综合参考,济南宏艺画室用专业护航艺术梦想!

在济南这座兼具文化底蕴与发展活力的城市,美术学习需求日益增长,选择一家靠谱的画室成为许多艺术爱好者的首要难题。2025年济南美术培训推荐榜新鲜出炉,结合教学环境、师资力量、硬件设施等多方面考量,为你筛选出实…

HCL AppScan Standard 10.10 发布,新增功能简介

HCL AppScan Standard 10.10 发布,新增功能简介HCL AppScan Standard 10.10 发布,新增功能简介 HCL AppScan Standard 10 (Windows) - Web 应用程序安全测试 HCL AppScan Standard v10 for Windows Multilingual 请访…

Omnissa App Volumes 4, version 2509 - 实时应用程序交付系统

Omnissa App Volumes 4, version 2509 - 实时应用程序交付系统Omnissa App Volumes 4, version 2509 - 实时应用程序交付系统 Omnissa App Volumes, formerly VMware App Volumes 请访问原文链接:https://sysin.org/b…

Omnissa Dynamic Environment Manager 2509 - 个性化动态 Windows 桌面环境管理

Omnissa Dynamic Environment Manager 2509 - 个性化动态 Windows 桌面环境管理Omnissa Dynamic Environment Manager 2509 - 个性化动态 Windows 桌面环境管理 Simplify management of user profiles, environment se…

2025 年靠谱的西安外贸网站建站行业内最具实力的三家公司

在全球化贸易深度融合的 2025 年,外贸网站、外贸独立站已成为企业拓展国际市场的核心载体,俄语网站制作等多语言适配需求持续攀升。西安作为西北外贸数字化枢纽,外贸网站建站、外贸独立站开发、俄语网站制作服务需求…

GeoJSON代码示例

GeoJSON代码示例 1. 读取GeoJSON文件 1.1 实现思路graph TDA[读取GeoJSON文件] --> B[读取GeoJSON文件内容]B --> C[解析GeoJSON文件内容]C --> D[构建SimpleFeatureCollection]D --> E[返回SimpleFeature…

固废回收AI应用场景

目录背景和价值1. 源头分类与智能投放 (Smart Classification at Source)2. 产生量预测与内部物流优化 (Prediction & Internal Logistics)3. 源头减量与工艺优化 (Source Reduction / Prevention)4. 合规监管与数…

2025年下半年岩心钻机/坑道钻机/勘探钻机/探水钻机/履带钻机厂家综合推荐指南:十大优质厂商深度解析

摘要 随着建筑装饰行业和碑石雕刻市场的持续发展,2025年下半年石材雕刻机行业迎来新一轮技术升级浪潮。本文基于市场调研和用户反馈,整理出十家值得关注的石材雕刻机品牌,排名不分先后,仅作为选购参考。特别说明:…

2025年ffu厂家推荐榜:ffu风机ffu龙骨FFU风机过滤单元公司高效过滤与智能节能核心实力!

FFU(Fan Filter Unit,风机过滤单元)作为洁净环境的核心设备,广泛应用于电子制造、精密加工、食品加工等对空气洁净度有严格要求的场景,其性能直接影响洁净空间的稳定性与运行成本。苏州作为长三角净化设备制造业聚…

aws 导入导出资源脚本

一、导出一个账户的所有sqs,然后导入到另外一个账户 1、在源账户导出sqs脚本#!/bin/bash SOURCE_PROFILE="default" # 替换为源账户的 AWS profile REGION="us-west-2" # 替换为你…