实验4

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);                         // 录入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.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     // 统计各分数段人数
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 }

 

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 }

image

问题1:std::string course_name;
std::vector grades;
std::array<int, 5> counts;
std::array<double, 5> rates;
course_name保存课程名,grades保存课程成绩,counts用数组保存各分数段人数,rates用数组保存各分数段人数占比。

问题2:不合法。push_back 不是 GradeCalc 类的公有接口,它是 std::vector 的成员函数,而 grades 是 GradeCalc 的 private 成员,在类外部无法直接访问 grades ,这违反了封装原则。

问题3:(1)compute()只会被调用一次,is_dirty标记用于显示成绩是否被更改,只有检测到成绩被更改才会调用compute()。
(2)不需要更改compute()调用位置,update_grade(index, new_grade)在被调用时只需要更改脏标记,在info()被调用时,compute()会自动被调用。

问题4:要增加"中位数"统计功能而不新增数据成员,我们需要在现有的函数中添加计算逻辑   在info()函数中添加

 1 double median() const;
 2 double GradeCalc::median() const {
 3  if (grades.empty()) {
 4       return 0.0;
 5     }
 6 std::vector<int> sorted_grades = grades;
 7   std::sort(sorted_grades.begin(), sorted_grades.end());
 8   size_t n = sorted_grades.size();
 9   if (n % 2 == 1) { // 奇数个成绩:取中间值
10        return sorted_grades[n / 2];
11     }
12   else {    // 偶数个成绩:取中间两个值的平均
13       return (sorted_grades[n / 2 - 1] + sorted_grades[n / 2]) / 2.0;
14     }
15 } // 修改info()函数,添加中位数显示
16  void GradeCalc::info() {
17  if (is_dirty) {
18      compute();
19 
20     }
21          std::cout << "课程名称:\t" << course_name << std::endl;
22          std::cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() << std::endl;
23          std::cout << "中位数:\t" << std::fixed << std::setprecision(2) << median() << std::endl;
24          std::cout << "最高分:\t" << max() << std::endl;
25          std::cout << "最低分:\t" << min() << std::endl;
26 }

问题5:compute中不能去掉这两行。如果去掉,当第二次和之后调用compute()时,前几次向counts和rates填入的人数数据会影响运算结果。

问题6:(1)无影响。程序仍然能正确运行。

   (2)有影响。去掉grades.reserve(n)后,会触发vector频繁进行自动扩容,增加了运行开销。

实验二

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);                        // 录入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.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     // 统计各分数段人数
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 }

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 }

屏幕截图 2025-12-02 205205

问题1:继承关系:
class GradeClac : private vector

问题2:当前继承方式下,基类 vector<int> 的接口不会自动成为 GradeCalc 的接口,因为是私有继承。

   不能编译通过。因为私有继承使基类的所有公有接口在派生类中都变为私有,外部无法直接调用

问题3:for(auto grade : grades)直接通过vector成员自带的接口,调用容器配套的vector::iterator迭代器,遍历容器。
for(int grade : *this)使用时,begin()、end()需要类自行提供,通过类的begin()、end()转发底层的vector容器的迭代器来遍历容器。

问题4:组合方案更适合。vector只是用来存储数据,应该是组合而不是用于继承;组合方案耦合度低,封装性更好。

实验3

Graph.hpp:

 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.cpp:

 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 }

task3.cpp

 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 }

屏幕截图 2025-12-02 205715

问题1:

(1)std::vector<Graph *> graphs;用于存储所有图形对象的指针集合。

(2)class Circle : public Graph;class Triangle : public Graph;class Rectangle : public Graph。

问题2:

继承:
class Circle : public Graph
class Triangle : public Graph
class Rectangle : public Graph

问题3:

Graph.hpp中:enum class GraphType中要加Star;
                             Star类的声明class Star : public Graph。
     Graph.cpp中:Star类实现void Star::draw();
                             GraphType str_to_GraphType(const std::string &s)要增加if (t == "Star")return GraphType::Star;
                             Graph *make_graph(const std::string &type)要增加case GraphType::Star:return new Star。
     demo3.cpp中:要增加canvas.add("Star")。
问题4:
(1)在 Canvas 类的析构函数中被释放。

  (2)优点:可以将继承自基类的不同派生类存放在一起,并且可以用基类指针进行批量管理,操作便捷。
缺点:用new分配的内存空间,如果没有delete,会导致内存泄漏;重复delete或者调用前被误释放,会产生野指针。必须通过Graph指针访问,不能直接访问派生类的特有成员。析构函数若为非虚函数,析构时会导致内存泄漏。

 实验4:
Toy.hpp:
 1 #ifndef TOY_HPP
 2 #define TOY_HPP
 3 
 4 #include <string>
 5 
 6 class Toy {
 7 protected:
 8     std::string name;
 9     std::string material;
10     std::string type;
11     std::string sound;
12 
13 public:
14     Toy(const std::string& n, const std::string& m, const std::string& t, const std::string& s);
15     virtual ~Toy() = default;
16 
17     virtual void doAction() const = 0;
18     
19     void playSound() const;
20     void displayInfo() const;
21     
22     std::string getName() const;
23     std::string getMaterial() const;
24     std::string getType() const;
25     std::string getSound() const;
26 };
27 
28 #endif

Toy.cpp

 1 #include "Toy.hpp"
 2 #include <iostream>
 3 
 4 Toy::Toy(const std::string& n, const std::string& m, const std::string& t, const std::string& s)
 5     : name(n), material(m), type(t), sound(s) {}
 6 
 7 void Toy::playSound() const {
 8     std::cout << "Playing: " << sound << std::endl;
 9 }
10 
11 void Toy::displayInfo() const {
12     std::cout << name << "\t" << material << "\t" << type << "\t" << sound << std::endl;
13 }
14 
15 std::string Toy::getName() const { return name; }
16 std::string Toy::getMaterial() const { return material; }
17 std::string Toy::getType() const { return type; }
18 std::string Toy::getSound() const { return sound; }

CatToy.hpp

 1 #ifndef CATTOY_HPP
 2 #define CATTOY_HPP
 3 
 4 #include "Toy.hpp"
 5 
 6 class CatToy : public Toy {
 7 public:
 8     CatToy(const std::string& name, const std::string& material, const std::string& sound);
 9     void doAction() const override;
10 };
11 
12 #endif

CatToy.cpp

1 #include "CatToy.hpp"
2 #include <iostream>
3 
4 CatToy::CatToy(const std::string& name, const std::string& material, const std::string& sound)
5     : Toy(name, material, "Cat", sound) {}
6 
7 void CatToy::doAction() const {
8     std::cout << name << " is licking its fur!" << std::endl;
9 }

DogToy.hpp

 1 #ifndef DOGTOY_HPP
 2 #define DOGTOY_HPP
 3 
 4 #include "Toy.hpp"
 5 
 6 class DogToy : public Toy {
 7 public:
 8     DogToy(const std::string& name, const std::string& material, const std::string& sound);
 9     void doAction() const override;
10 };
11 
12 #endif

DogToy.cpp

1 #include "DogToy.hpp"
2 #include <iostream>
3 
4 DogToy::DogToy(const std::string& name, const std::string& material, const std::string& sound)
5     : Toy(name, material, "Dog", sound) {}
6 
7 void DogToy::doAction() const {
8     std::cout << name << " is wagging tail!" << std::endl;
9 }

BearToy.hpp

 1 #ifndef BEARTOY_HPP
 2 #define BEARTOY_HPP
 3 
 4 #include "Toy.hpp"
 5 
 6 class BearToy : public Toy {
 7 public:
 8     BearToy(const std::string& name, const std::string& material, const std::string& sound);
 9     void doAction() const override;
10 };
11 
12 #endif

BearToy.cpp

1 #include "BearToy.hpp"
2 #include <iostream>
3 
4 BearToy::BearToy(const std::string& name, const std::string& material, const std::string& sound)
5     : Toy(name, material, "Bear", sound) {}
6 
7 void BearToy::doAction() const {
8     std::cout << name << " is waving its hands!" << std::endl;
9 }

ToyFactory.hpp

 1 #ifndef TOYFACTORY_HPP
 2 #define TOYFACTORY_HPP
 3 
 4 #include <vector>
 5 #include <string>
 6 #include "Toy.hpp"
 7 
 8 class ToyFactory {
 9 private:
10     std::vector<Toy*> toys;
11 
12 public:
13     ~ToyFactory();
14     
15     bool addToy(Toy* toy);
16     bool deleteToy(const std::string& name);
17     
18     void displayAllToys() const;
19     void playAllSounds() const;
20     void doAllActions() const;
21     
22     int getToyCount() const;
23 };
24 
25 #endif

ToyFactory.cpp

 1 #include "ToyFactory.hpp"
 2 #include <iostream>
 3 #include <algorithm>
 4 
 5 ToyFactory::~ToyFactory() {
 6     for (Toy* toy : toys) {
 7         delete toy;
 8     }
 9 }
10 
11 bool ToyFactory::addToy(Toy* toy) {
12     toys.push_back(toy);
13     std::cout << "Success To Add Toy: " << toy->getName() << std::endl;
14     return true;
15 }
16 
17 bool ToyFactory::deleteToy(const std::string& name) {
18     for (auto it = toys.begin(); it != toys.end(); ++it) {
19         if ((*it)->getName() == name) {
20             delete *it;
21             toys.erase(it);
22             std::cout << "Del Success" << std::endl;
23             return true;
24         }
25     }
26     return false;
27 }
28 
29 void ToyFactory::displayAllToys() const {
30     std::cout << "Toys Information:" << std::endl;
31     for (const Toy* toy : toys) {
32         toy->displayInfo();
33     }
34 }
35 
36 void ToyFactory::playAllSounds() const {
37     for (const Toy* toy : toys) {
38         toy->playSound();
39     }
40 }
41 
42 void ToyFactory::doAllActions() const {
43     for (const Toy* toy : toys) {
44         toy->doAction();
45     }
46 }
47 
48 int ToyFactory::getToyCount() const {
49     return toys.size();
50 }

task4.cpp

 1 #include <iostream>
 2 #include "ToyFactory.hpp"
 3 #include "CatToy.hpp"
 4 #include "DogToy.hpp"
 5 #include "BearToy.hpp"
 6 
 7 int main() {
 8     ToyFactory factory;
 9     
10     factory.addToy(new CatToy("kitty", "cotton", "MorningMeow"));
11     factory.addToy(new DogToy("Bruce", "Plastic", "Erica"));
12     factory.addToy(new BearToy("Teddy", "Cotton", "Hotel California"));
13     
14     std::cout << std::endl;
15     
16     factory.displayAllToys();
17     
18     std::cout << std::endl;
19     
20     factory.doAllActions();
21     
22     std::cout << std::endl;
23     
24     factory.playAllSounds();
25     
26     std::cout << std::endl;
27     
28     factory.deleteToy("kitty");
29     
30     std::cout << std::endl;
31     
32     factory.displayAllToys();
33     
34     return 0;
35 }

设计理由:

继承 + 虚函数(多态性):
Toy 是抽象基类,包含纯虚函数 doAction()
派生类(CatToy, DogToy, BearToy)覆盖 doAction() 实现特定行为
允许通过 Toy* 指针统一处理所有玩具类型
ToyFactory(组合):
包含 std::vector<Toy*> 管理所有玩具对象
演示组合关系:工厂"拥有"玩具集合
提供统一的管理接口(添加、删除、显示、播放)
关键设计决策:
抽象基类:确保所有玩具实现必需的接口
虚函数:为特殊动作实现运行时多态性
工厂模式:集中对象创建和管理
关注点分离:显示逻辑、声音播放、动作执行是独立的方法
可扩展性:
可以通过继承 Toy 添加新的玩具类型
工厂方法无需修改即可处理新类型(开闭原则)

屏幕截图 2025-12-02 212428

 


 

posted @ 2025-12-02 21:24  zhj910  阅读(5)  评论(0)    收藏  举报