实验四 组合与继承
实验任务一:
源码:
#pragma once #include <vector> #include <array> #include <string> class GradeCalc{ public: GradeCalc(const std::string &cname); void input(int n);//录入n个成绩 void output() const; void sort(bool ascending = false);//默认降序 int min() const; int max() const; double average() const; void info();//输出课程成绩 private: void compute();//成绩统计 private: std::string course_name; std::vector<int> grades; std::array<int,5> counts;//保存各分数段人数 std::array<double,5> rates;//保存各分数段人数占比 bool is_dirty;//脏标记,记录是否成绩信息有变更 };
#include <algorithm> #include <array> #include <cstdlib>//包含C标准库的通用工具 #include <iomanip>//格式化输入输出 #include <iostream> #include <numeric>//数值算法(如累加容器元素,部分和等) #include <string> #include <vector> #include "GradeCalc.hpp" GradeCalc::GradeCalc(const std::string &cname):course_name{cname},is_dirty{true}{ counts.fill(0); rates.fill(0); } void GradeCalc::input(int n){ if(n < 0){ std::cerr << "无效输入!人数不能为负数\n"; //cerr(标准错误输出流) //与cout是两个独立的流,可通过系统分离(如将普通输出写入文件,错误输出仍显示在屏幕) //cerr无缓冲 std::exit(1); } grades.reserve(n);//reserve提前预留至少能容纳n个元素的内存空间,不改变容器实际元素数量 int grade; for(int i = 0;i < n;){ std::cin >> grade; if(grade < 0 || grade > 100){ std::cerr << "无效输入!分数须在[0,100]\n"; continue; } grades.push_back(grade); ++i; } is_dirty = true;//设置脏标记:成绩信息有变更 } void GradeCalc::output() const{ for(auto grade:grades) std::cout << grade << ' '; std::cout << std::endl; } void GradeCalc::sort(bool ascending){ if(ascending) std::sort(grades.begin(),grades.end());//sort默认升序 else std::sort(grades.begin(),grades.end(),std::greater<int>());//greater专门用来表示“大于”关系//()表示创建一个实例 } int GradeCalc::min() const{ if(grades.empty()) return -1; //min_element函数定义在<algorithm>头文件中,默认<比较 auto it = std::min_element(grades.begin(),grades.end()); return *it;//迭代器it是指针类型 } int GradeCalc::max() const{ if(grades.empty()) return -1; auto it = std::max_element(grades.begin(),grades.end()); return *it; } double GradeCalc::average() const{ if(grades.empty()) return 0.0; double avg = std::accumulate(grades.begin(),grades.end(),0.0) / grades.size(); return avg; } void GradeCalc::info(){ if(is_dirty) compute(); std::cout << "课程名称:\t" << course_name <<std::endl; std::cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() << std::endl; //std::fixed来自<iomanip>,指定浮点数以固定小数点格式进行输出,通常与std::setprecision()搭配使用 std::cout << "最高分:\t" << max() << std::endl; std::cout << "最低分:\t" << min() << std::endl; const std::array<std::string,5> grade_range{"[0,60)","[60,70)","[70,80)","[80,90)","[90,100]"}; for(int i = grade_range.size()-1;i >= 0;--i) std::cout << grade_range[i] << "\t: " << counts[i] << "人\t" << std::fixed << std::setprecision(2) << rates[i]*100 << "%\n"; } void GradeCalc::compute(){ if(grades.empty()) return; counts.fill(0); rates.fill(0.0); //统计各分数段人数 for(auto grade:grades){ if(grade < 60) ++counts[0]; else if (grade < 70) ++counts[1]; else if (grade < 80) ++counts[2]; else if (grade < 90) ++counts[3]; else ++counts[4]; } //统计各分数段比例 for(int i = 0;i < rates.size();i++) rates[i] = counts[i] * 1.0/grades.size(); is_dirty = false; }
#include <iostream> #include <string> #include "GradeCalc.hpp" void test(){ GradeCalc cl("OOP"); std::cout << "录入成绩:\n"; cl.input(5); std::cout << "输出成绩:\n"; cl.output(); std::cout << "排序后成绩:\n"; cl.sort();cl.output(); std::cout << "*************成绩统计信息*************\n"; cl.info(); } int main(){ test(); }
运行测试结果截图:

回答问题:
问题1:组合关系识别
GradeCalc 类声明中,逐行写出所有体现"组合"关系的成员声明,并用一句话说明每个被组合对象的功能。
答:std::string course_name; //记录课程名称
问题2:接口暴露理解
如在test模块中这样使用,是否合法?如不合法,解释原因。
GradeCalc c("OOP"); c.inupt(5); c.push_back(97); // 合法吗?
答:不合法。push_back是std::vector类中提供的接口,可以向vector中添加数据元素。但是GradeCalc类中std::vector<int>grades是私有成员,只能在类的内部访问。而GradeCalc类中也并没有提供push_back的公有接口。
问题3:架构设计分析
当前设计方案中, compute 在 info 模块中调用:
(1)连续打印3次统计信息, compute 会被调用几次?标记is_dirty起到什么作用?
答:1次。is_dirty是脏标记,用来判断对象成绩信息是否变更。
(2)如新增update_grade(index, new_grade) ,这种设计需要更改 compute 调用位置吗?简洁说明理由。
答:update_grade(index, new_grade) 这种设计,需要更改 compute 调用位置。当通过input和update添加或修改了成绩后is_dirty = true,compute调用位置需放函数最后。在info中,先用is_dirty来判断成绩信息是否变更,如果变更需要调用comput重新统计成绩信息,再执行输出逻辑。
问题4:功能扩展设计
要增加"中位数"统计,不新增数据成员怎么做?在哪个函数里加?写出伪代码。
答:不新增数据成员,可以新增成员函数median,利用数据成员里vector<int> grades通过索引找到中位数。在info里添加median()输出。
代码:
double GradeCalc::median() const{ if(grades.empty()) return 0.0; //中位数根据下标索引确定位置,排序前后数据会发生变化,所以需要先排序再求索引下标。 std::vector<int> sorted_grades = grades;//新vector sorted_grades不会直接修改原grades信息 std::sort(sorted_grades.begin(),sorted_grades.end()); int n = sorted_grades.size(); if(n % 2 == 1)//奇数个取中间 return sorted_grades[n / 2]; else return (sorted_grades[n / 2 - 1] + sorted_grades[n / 2 + 1]) / 2.0;//偶数个求平均 }
运行结果测试截图:(是否sort并不影响中位数正确输出)

问题5:数据状态管理
GradeCalc 和 compute 中都包含代码: counts.fill(0); rates.fill(0); 。 compute 中能否去掉这两行?如去掉,在哪种使用场景下会引发统计错误?
答:不能。如果去掉,改变已经定义的GradeCalc类型对象的成绩信息时,counts和rates并未重新置0,counts和rates会在原有的基础上增加。
问题6:内存管理理解
input 模块中代码 grades.reserve(n); 如果去掉:
(1)对程序功能有影响吗?(去掉重新编译、运行,观察功能是否受影响)
答:对程序功能无影响。

(2)对性能有影响吗?如有影响,用一句话陈述具体影响
答:对性能有影响。容器的底层存储一般是连续的内存块,当容器中元素数量超过内存块容量时需要扩容,而扩容会消耗大量时间,reserve能提前预留至少能容纳n个元素的内存空间而且不改变容器实际元素数量,后续添加元素时只要不超过n,就不会触发扩容,提高效率。
实验任务二:
源码:
#pragma once #include <vector> #include <array> #include <string> class GradeCalc:private std::vector<int>{ public: GradeCalc(const std::string &cname); void input(int n);//录入n个成绩 void output() const; void sort(bool ascending = false);//默认降序 int min() const; int max() const; double average() const; void info();//输出课程成绩 private: void compute();//成绩统计 private: std::string course_name; std::vector<int> grades; std::array<int,5> counts;//保存各分数段人数 std::array<double,5> rates;//保存各分数段人数占比 bool is_dirty;//脏标记,记录是否成绩信息有变更 };
#include <algorithm> #include <array> #include <cstdlib>//包含C标准库的通用工具 #include <iomanip>//格式化输入输出 #include <iostream> #include <numeric>//数值算法(如累加容器元素,部分和等) #include <string> #include <vector> #include "GradeCalc.hpp" GradeCalc::GradeCalc(const std::string &cname):course_name{cname},is_dirty{true}{ counts.fill(0); rates.fill(0); } void GradeCalc::input(int n){ if(n < 0){ std::cerr << "无效输入!人数不能为负数\n"; //cerr(标准错误输出流) //与cout是两个独立的流,可通过系统分离(如将普通输出写入文件,错误输出仍显示在屏幕) //cerr无缓冲 return; } this->reserve(n);//reserve提前预留至少能容纳n个元素的内存空间,不改变容器实际元素数量 int grade; for(int i = 0;i < n;){ std::cin >> grade; if(grade < 0 || grade > 100){ std::cerr << "无效输入!分数须在[0,100]\n"; continue; } this->push_back(grade); ++i; } is_dirty = true;//设置脏标记:成绩信息有变更 } void GradeCalc::output() const{ for(auto grade:*this) std::cout << grade << ' '; std::cout << std::endl; } void GradeCalc::sort(bool ascending){ if(ascending) std::sort(this->begin(),this->end());//sort默认升序 else std::sort(this->begin(),this->end(),std::greater<int>());//greater专门用来表示“大于”关系//()表示创建一个实例 } int GradeCalc::min() const{ if(this->empty()) return -1; //min_element函数定义在<algorithm>头文件中,默认<比较 auto it = std::min_element(this->begin(),this->end()); return *it;//迭代器it是指针类型 } int GradeCalc::max() const{ if(this->empty()) return -1; auto it = std::max_element(this->begin(),this->end()); return *it; } double GradeCalc::average() const{ if(this->empty()) return 0.0; double avg = std::accumulate(this->begin(),this->end(),0.0) / this->size(); return avg; } void GradeCalc::info(){ if(is_dirty) compute(); std::cout << "课程名称:\t" << course_name <<std::endl; std::cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() << std::endl; // std::cout << "中位数:\t" << median() << std::endl; //std::fixed来自<iomanip>,指定浮点数以固定小数点格式进行输出,通常与std::setprecision()搭配使用 std::cout << "最高分:\t" << max() << std::endl; std::cout << "最低分:\t" << min() << std::endl; const std::array<std::string,5> grade_range{"[0,60)","[60,70)","[70,80)","[80,90)","[90,100]"}; for(int i = grade_range.size()-1;i >= 0;--i) std::cout << grade_range[i] << "\t: " << counts[i] << "人\t" << std::fixed << std::setprecision(2) << rates[i]*100 << "%\n"; } void GradeCalc::compute(){ if(this->empty()) return; counts.fill(0); rates.fill(0.0); //统计各分数段人数 for(auto grade:*this){ if(grade < 60) ++counts[0]; else if (grade < 70) ++counts[1]; else if (grade < 80) ++counts[2]; else if (grade < 90) ++counts[3]; else ++counts[4]; } //统计各分数段比例 for(int i = 0;i < rates.size();i++) rates[i] = counts[i] * 1.0/this->size(); is_dirty = false; }
#include <iostream> #include <string> #include "GradeCalc.hpp" void test(){ GradeCalc cl("OOP"); std::cout << "录入成绩:\n"; cl.input(5); std::cout << "输出成绩:\n"; cl.output(); std::cout << "*************排序前成绩统计信息*************\n"; cl.info(); std::cout << "排序后成绩:\n"; cl.sort();cl.output(); std::cout << "*************成绩统计信息*************\n"; cl.info(); } int main(){ test(); }
运行结果测试截图:

回答问题:
问题1:继承关系识别
写出 GradeCalc 类声明体现"继承"关系的完整代码行。
class GradeCalc:private std::vector<int>
问题2:接口暴露理解
当前继承方式下,基类 vector 的接口会自动成为 GradeCalc 的接口吗? 如在test模块中这样用,能否编译通过?用一句话解释原因。
答:当前private继承方式下,基类vector的接口会自动成为GradeCalc的私有接口。如在test模块中使用,无法编译通过。因为GradeCalc从vector中继承过来的接口是private类型私有接口,只能在类中访问,无法在test中外部访问。
问题3:数据访问差异
对比继承方式与组合方式内部实现数据访问的一行典型代码。说明两种方式下的封装差异带来的数据访问接口差异。
| 继承方式 | vs | 组合方式 |
this->push_back(grade);
|
grades.push_back(grade);
|
差异:GradeCalc继承的vector接口相当于它自身内部有这些接口,可以通过this指针访问接口;而组合方式中GradeCalc本身内部并没有vector所拥有的接口,只是因为类vector内嵌在其中,所以GradeCalc可以通过std::vector使用vector的接口。
问题4:组合 vs. 继承方案选择
你认为组合方案和继承方案,哪个更适合成绩计算这个问题场景?简洁陈述你的结论和理由。
答:我认为组合方案更适合成绩计算这个问题场景。首先需要明确的是类GradeCalc是一个计算器类,它的核心是实现成绩的一系列计算统计和输出。而vector中的接口是用来做细节部分的成绩处理,GradeCalc的核心功能与vector中的接口功能并不一致。虽然组合和继承方案都能正确得到最终结果,但从逻辑角度而言,组合方案更加清晰地展现了计算器类和vector类的内在逻辑关系。
实验任务三:
源码:
#pragma once #include <string> #include <vector> enum class GraphType {circle,triangle,rectangle};//枚举类enum class属于枚举类型 //Graph类定义 class Graph{ public: virtual void draw(){}; virtual ~Graph() = default;//虚析构函数 //默认析构函数 }; //Circle类声明 class Circle : public Graph{ public: void draw(); }; //Triangle类声明 class Triangle : public Graph{ public: void draw(); }; //Rectangle类声明 class Rectangle : public Graph{ public: void draw(); }; //Canvas类声明 class Canvas{ public: void add(const std::string& type);//根据字符串添加图形 void paint() const;//使用统一接口绘制所有图形 ~Canvas();//手动释放资源 private: std::vector<Graph*> graphs; }; //工具函数 GraphType str_to_GraphType(const std::string& s);//字符串转枚举类型 Graph* make_graph(const std::string& type);//创建图形,返回堆对象指针
#include <algorithm> #include <cctype> #include <iostream> #include <string> #include "Graph.hpp" //Circle类实现 void Circle::draw(){ std::cout << "draw a circle...\n"; } //Triangle类实现 void Triangle::draw(){ std::cout << "draw a triangle...\n"; } //Rectangle类实现 void Rectangle::draw(){ std::cout << "draw a rectangle...\n"; } //Canvas类实现 void Canvas::add(const std::string& type){ Graph* g = make_graph(type); if(g) graphs.push_back(g);//根据返回的堆对象指针创建相应的图形 } void Canvas::paint() const{ for(Graph* g:graphs) g->draw();//调用每一个graphs中具体图形的draw函数 } Canvas::~Canvas(){ for(Graph* g :graphs) delete g;//释放内存 } //工具函数实现 //字符串 -> 枚举转换//把用户的字符串指令转成程序内部能识别的枚举标记 GraphType str_to_GraphType(const std::string& s){ std::string t = s; //批量处理容器元素//将s中所有字符转为小写,并把结果存到字符串t中,解决“字符串大小写不匹配”的问题 std::transform(s.begin(),s.end(),t.begin(),[](unsigned char c){return std::tolower(c);}); if(t == "circle") return GraphType::circle; if(t == "triangle") return GraphType::triangle; if(t == "rectangle") return GraphType::rectangle; return GraphType::circle;//缺省返回 } //创建图形,返回堆对象指针 Graph* make_graph(const std::string& type){ switch(str_to_GraphType(type)){ case GraphType::circle: return new Circle;//在堆内存中创建对应图形的对象,并返回该堆对象的指针 case GraphType::triangle: return new Triangle; case GraphType::rectangle: return new Rectangle; default: return nullptr;//若字符串无法转成有效枚举值,返回空指针 } }
task3.cpp运行结果测试截图:

回答问题:
问题1:对象关系识别
(1)写出Graph.hpp中体现"组合"关系的成员声明代码行,并用一句话说明被组合对象的功能。
答:功能:在Canvas中存储需要绘制的图形类型。
private: 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() 运行结果会有何不同?
答:会没有输出结果,即无法绘制对应图形。因为不声明virtual,g->draw()会调用基类的draw,无法让派生类覆盖基类中的draw()函数,无法实现多态。

(2)若 Canvas 类 std::vector<Graph*> 改成 std::vector<Graph> ,会出现什么问题?
答:会导致图形内存无法分配,无法绘制图形。make_graph()返回的是Graph*,而vector<Graph>存放Graph类型对象,类型不匹配。创建图形的核心代码是Graph* make_graph()函数,该函数在堆内存中创建对应图形的对象,并返回该堆对象的指针。而Canvas根据返回的堆对象指针创建相应的图形,若把指针类型改为Graph类型,则无法根据指针创建相应图形。

(3)若 ~Graph() 未声明成虚函数,会带来什么问题?
答:无法调用派生类析构函数,只调用基类析构函数,继而无法释放派生类调用内存,造成内存泄漏
问题3:扩展性思考
若要新增星形 Star ,需在哪些文件做哪些改动?逐一列出。
答:Graph.hpp : 枚举类GraphType里新增Star类型 ; 新增Star类声明
Graph.cpp : Star类实现 ; str_to_GraphType函数中新增Star字符串转换为枚举类型功能 ; make_graph函数中返回star类型的堆指针
taskk3.cpp : test()中新增语句 canvas.add("Star");
enum class GraphType {circle,triangle,rectangle,star};
//Star类声明 class Star : public Graph{ public: void draw(); };
//Star类实现 void Star::draw(){ std::cout << "draw a Star...\n"; }
if(t == "star") return GraphType::star;
case GraphType::star: return new Star;
canvas.add("Star");
问题4:资源管理
观察 make_graph 函数和 Canvas 析构函数:
(1) make_graph 返回的对象在什么地方被释放?
答:所有图形绘制完后一起释放

(2)使用原始指针管理内存有何利弊?
答: 利:可以直接操作内存地址,比如return new Circle手动分配内存。
弊:容易遗漏delete释放内存,造成内存泄漏,比如delete g手动释放内存 ;
容易产生野指针问题,造成未定义行为,比如:若未将指针指控,后续易导致程序无法正确运行。
default: return nullptr;
实验任务四:
问题场景描述:
问题需求是集中统一展示玩具工厂中所有玩具的功能。以Toy类为基类,扩展出不同功能类型的派生类,再通过ToyFactory类集中管理不同种类玩具,并提供统一接口尝试所有玩具的不同功能。
各类关系及设计理由:
Toy类为基类,封装了玩具的核心数据成员,如名称、颜色、类型、尺寸,还有通用功能接口,如语音交互、录音播放、发光、名称获取,并通过虚函数和虚析构函数保证多态。Companion、Decoration、Interaction、Portable四类具体玩具公有继承Toy类,并重写对应虚函数。ToyFactory类通过组合关系内嵌vector,统一提供玩具添加、信息展示的接口,借助多态实现不同类型玩具的统一调用。
源码:
#pragma once #include <string> enum class ToyType{companion,decoration,interaction,portable};//陪伴、装饰、互动、便携类型 //玩具类 class Toy{ public: Toy():Toy_name("未命名玩具"){} Toy(const std::string& toy_name):Toy_name{toy_name}{} virtual void Voice_Interaction();//语音交互功能 virtual void Play_function();//录音播放功能 virtual void Light_up();//发光功能 virtual ~Toy() = default;//默认虚析构函数 public: virtual std::string get_name() const; private: std::string Toy_name;//玩具名称 std::string color;//玩具颜色 ToyType Toy_Type;//玩具类型 int size;//玩具尺寸 }; //companion类声明 class Companion : public Toy{ public: Companion() = default; Companion(const std::string& toy_name):Toy{toy_name}{} void Voice_Interaction(); void Play_function(); void Light_up(); ~Companion(); std::string get_name() const; }; //Decoration类声明 class Decoration : public Toy{ public: Decoration() = default; Decoration(std::string& toy_name):Toy{toy_name}{} void Voice_Interaction(); void Play_function(); void Light_up(); ~Decoration(); std::string get_name() const; }; //Interaction类声明 class Interaction : public Toy{ public: Interaction() = default; Interaction(std::string& toy_name):Toy{toy_name}{} void Voice_Interaction(); void Play_function(); void Light_up(); ~Interaction(); std::string get_name() const; }; //Portable类声明 class Portable : public Toy{ public: Portable() = default; Portable(std::string& toy_name):Toy{toy_name}{} void Voice_Interaction(); void Play_function(); void Light_up(); ~Portable(); std::string get_name() const; }; //工具函数 ToyType str_to_ToyType(const std::string& s);//字符串转枚举类型 // std::string ToyType_to_str(ToyType type); // 枚举转字符串 Toy* make_toy(const std::string& type);
#include "Toy.hpp" #include <iostream> //Toy类虚函数默认实现 void Toy::Voice_Interaction(){ std::cout << "该玩具不支持语音交互功能" << std::endl; } void Toy::Play_function(){ std::cout << "该玩具不支持录音播放功能" << std::endl; } void Toy::Light_up(){ std::cout << "该玩具不支持发光功能" << std::endl; } std::string Toy::get_name() const{ return Toy_name; } //Companion类实现 void Companion::Voice_Interaction(){ std::cout << "陪伴类玩具:正在进行语音聊天互动" << std::endl; } void Companion::Play_function(){ std::cout << "陪伴类玩具:播放录制的故事" << std::endl; } void Companion::Light_up(){ std::cout << "陪伴类玩具:柔和灯光已亮起(助眠模式)" << std::endl; } Companion::~Companion(){ } std::string Companion::get_name() const { return "陪伴类"; } //Decoration类实现 void Decoration::Voice_Interaction(){ std::cout << "装饰类玩具:不支持语音交互功能" << std::endl; } void Decoration::Play_function(){ std::cout << "装饰类玩具:不支持录音播放功能" << std::endl; } void Decoration::Light_up(){ std::cout << "装饰类玩具:彩色氛围灯已亮起(装饰模式)" << std::endl; } Decoration::~Decoration(){ } std::string Decoration::get_name() const{ return "装饰类"; } //Interaction类实现 void Interaction::Voice_Interaction(){ std::cout << "互动类玩具:正在识别语音指令" << std::endl; } void Interaction::Play_function(){ std::cout << "互动类玩具:播放互动游戏的提示音" << std::endl; } void Interaction::Light_up(){ std::cout << "互动类玩具:灯光配合游戏节奏闪烁" << std::endl; } Interaction::~Interaction(){ } std::string Interaction::get_name() const{ return "互动类"; } //Portable类实现 void Portable::Voice_Interaction(){ std::cout << "便携类玩具:简短语音对话" << std::endl; } void Portable::Play_function(){ std::cout << "便携类玩具:播放简短歌曲片段" << std::endl; } void Portable::Light_up(){ std::cout << "便携类玩具:指示灯亮起" << std::endl; } Portable::~Portable(){ } std::string Portable::get_name() const{ return "便携类"; } ToyType str_to_ToyType(const std::string& s){ if(s == "companion") return ToyType::companion; if(s == "decoration") return ToyType::decoration; if(s == "interaction") return ToyType::interaction; if(s == "portable") return ToyType::portable; else{ std::cerr << "无效类型" << std::endl; exit(1);//非void类型终止程序 } } Toy* make_toy(const std::string& type){ ToyType toyType = str_to_ToyType(type); switch (toyType){ case ToyType::companion: return new Companion(); case ToyType::decoration: return new Decoration(); case ToyType::interaction: return new Interaction(); case ToyType::portable: return new Portable(); default: return nullptr; } }
#pragma once #include <vector> #include "Toy.hpp" //玩具工厂类 class ToyFactory{ public: void info() const;//显示工厂玩具信息 void addToy(Toy* toy); //添加玩具到工厂 ~ToyFactory(); private: std::vector<Toy*> Toy_info; //存储玩具指针 };
#include "Toy.hpp" #include "ToyFactory.hpp" #include <iostream> //向工厂添加玩具 void ToyFactory::addToy(Toy* toy) { if (toy){ Toy_info.push_back(toy); std::cout << "玩具已添加到工厂" << std::endl; } else{ std::cerr << "无法添加空玩具" << std::endl; } } //info()显示工厂所有玩具的信息 void ToyFactory::info() const{ std::cout << "\n****************************************************" << std::endl; std::cout << "\t\t所有玩具功能信息" << std::endl; std::cout << "****************************************************\n" << std::endl; for (int i = 0; i < Toy_info.size(); i++) { std::cout << "[" << i + 1 << "]" << Toy_info[i]->get_name() << "玩具功能测试:" << std::endl; Toy_info[i]->Voice_Interaction(); Toy_info[i]->Play_function(); Toy_info[i]->Light_up(); std::cout << "\n"; } std::cout << "****************************************************\n" << std::endl; } ToyFactory::~ToyFactory() { for (auto& toy : Toy_info) { delete toy; } Toy_info.clear(); }
#include "Toy.hpp" #include "ToyFactory.hpp" #include <iostream> int main(){ ToyFactory factory; factory.addToy(make_toy("companion")); factory.addToy(make_toy("decoration")); factory.addToy(make_toy("interaction")); factory.addToy(make_toy("portable")); factory.info(); return 0; }
运行测试结果截图:


浙公网安备 33010602011771号