oop实验四
实验四
test1:
源代码:
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) 12 : course_name{cname}, is_dirty{true} { 13 counts.fill(0); // 分数段计数初始化为0 14 rates.fill(0.0); // 分数段占比初始化为0.0 15 } 16 17 // 录入成绩:循环逻辑,确保合法成绩才存入 18 void GradeCalc::input(int n) { 19 if (n < 0) { 20 std::cerr << "无效输入! 人数不能为负数\n"; 21 std::exit(1); 22 } 23 grades.reserve(n); 24 int grade; 25 for (int i = 0; i < n;) { // 循环变量i仅在合法输入时递增 26 std::cin >> grade; 27 if (grade < 0 || grade > 100) { 28 std::cerr << "无效输入! 分数须在[0,100]\n"; 29 continue; 30 } 31 grades.push_back(grade); 32 ++i; 33 } 34 is_dirty = true; 35 } 36 37 // 输出成绩:语法,确保循环正确遍历 38 void GradeCalc::output() const { 39 for (auto grade : grades) 40 std::cout << grade << ' '; 41 std::cout << std::endl; 42 } 43 44 // 排序:排序后置脏标记,确保统计同步 45 void GradeCalc::sort(bool ascending) { 46 if (ascending) 47 std::sort(grades.begin(), grades.end()); 48 else 49 std::sort(grades.begin(), grades.end(), std::greater<int>()); 50 is_dirty = true; //排序后成绩变更,置脏标记 51 } 52 53 // 返回最低分:语法,确保空判断正确 54 int GradeCalc::min() const { 55 if (grades.empty()) 56 return -1; 57 auto it = std::min_element(grades.begin(), grades.end()); 58 return *it; 59 } 60 61 // 返回最高分:语法,确保空判断正确 62 int GradeCalc::max() const { 63 if (grades.empty()) 64 return -1; 65 auto it = std::max_element(grades.begin(), grades.end()); 66 return *it; 67 } 68 69 // 返回平均分:语法,确保浮点数计算 70 double GradeCalc::average() const { 71 if (grades.empty()) 72 return 0.0; 73 double sum = std::accumulate(grades.begin(), grades.end(), 0.0); //0.0确保浮点数累加 74 return sum / grades.size(); 75 } 76 77 // 计算统计:分数段逻辑,补充重置统计数组 78 void GradeCalc::compute() { 79 if (grades.empty()) 80 return; 81 counts.fill(0); // 每次计算前重置计数,避免历史数据干扰 82 rates.fill(0.0); // 每次计算前重置占比 83 84 // 补充大括号,确保分支逻辑正确 85 for (auto grade : grades) { 86 if (grade < 60) 87 ++counts[0]; 88 else if (grade < 70) 89 ++counts[1]; 90 else if (grade < 80) 91 ++counts[2]; 92 else if (grade < 90) 93 ++counts[3]; 94 else 95 ++counts[4]; 96 } 97 98 //确保浮点数计算占比 99 int total = grades.size(); 100 for (int i = 0; i < rates.size(); ++i) { 101 rates[i] = counts[i] * 1.0 / total; //1.0避免整数除法精度丢失 102 } 103 104 is_dirty = false; 105 } 106 107 // 输出统计信息:优化格式,确保逻辑正确 108 void GradeCalc::info() { 109 if (is_dirty) 110 compute(); 111 112 std::cout << "课程名称:\t" << course_name << std::endl; 113 std::cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() << std::endl; 114 std::cout << "最高分:\t" << max() << std::endl; 115 std::cout << "最低分:\t" << min() << std::endl; 116 117 const std::array<std::string, 5> grade_range{ 118 "[0, 60) ", "[60, 70)", "[70, 80)", "[80, 90)", "[90, 100]"}; 119 std::cout << "分数段分布:\n"; 120 for (int i = grade_range.size() - 1; i >= 0; --i) { 121 std::cout << grade_range[i] << "\t: " << counts[i] << "人\t" 122 << std::fixed << std::setprecision(2) << rates[i] * 100 << "%\n"; 123 } 124 }
1 #pragma once 2 #include <vector> 3 #include <array> 4 #include <string> 5 6 class GradeCalc { 7 public: 8 GradeCalc(const std::string &cname); 9 void input(int n); // 录入n个成绩 10 void output() const; // 输出成绩( 11 void sort(bool ascending = false); // 排序 12 int min() const; // 返回最低分(未录入返回-1) 13 int max() const; // 返回最高分(未录入返回-1) 14 double average() const; // 返回平均分(未录入返回0.0) 15 void info(); // 输出课程成绩统计信息 16 17 private: 18 void compute(); 19 std::string course_name; //组合-> 课程名 20 std::vector<int> grades; // ->存储课程成绩 21 std::array<int, 5> counts; // ->各分数段人数 22 std::array<double, 5> rates; // ->各分数段占比 23 bool is_dirty; 24 };
#include <iostream> #include <string> #include "GradeCalc.hpp" void test() { GradeCalc c1("OOP"); std::cout << "录入成绩:\n"; c1.input(5); std::cout << "输入成绩:\n"; c1.output(); std::cout << "\n降序排序后成绩:\n"; c1.sort(); c1.output(); std::cout << "*************成绩统计信息*************\n"; c1.info(); } int main() { test(); return 0; }
运行结果:

问题:
1.
std::vector<int> grades:存课程成绩;
std::array<int,5> counts:存各分数段人数;
std::array<double,5> rates:存各分数段占比;
std::string course_name:存课程名
源代码里使用“->”标注了
2.
不合法。inupt拼写错,应为input;二是push_back是vector私有成员的接口,GradeCalc未暴露,外部不能调用。
3.
1) 1 次。is_dirty标记成绩是否改变了,不变时避免重复计算。
2) 不用改。新增update_grade时设is_dirty=true,info会自动调用compute。
4.在GradeCalc加median()函数,用grades拷贝排序后计算:
double median() const {
if (grades.empty()) return 0.0;
auto temp = grades;
sort(temp.begin(), temp.end());
return temp.size()%2 ? temp[temp.size()/2] : (temp[temp.size()/2-1]+temp[temp.size()/2])/2.0;
}
5.不能删。删后成绩变更时,counts和rates会叠加导致统计错误
6.
1) 无影响,仍能正常运行。
2) 有影响,大量成绩录入时,内存频繁扩容,运行变慢
test2:
源代码:
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.0); 14 } 15 16 void GradeCalc::input(int n) { 17 if(n < 0) { 18 std::cerr << "无效输入! 人数不能为负数\n"; 19 return; 20 } 21 this->reserve(n); 22 23 int grade; 24 for(int i = 0; i < n;) { 25 std::cin >> grade; 26 if(grade < 0 || grade > 100) { 27 std::cerr << "无效输入! 分数须在[0,100]\n"; 28 continue; 29 } 30 this->push_back(grade); 31 ++i; 32 } 33 is_dirty = true; 34 } 35 36 void GradeCalc::output() const { 37 for(auto grade: *this) { 38 std::cout << grade << ' '; 39 } 40 std::cout << std::endl; 41 } 42 43 void GradeCalc::sort(bool ascending) { 44 if(ascending) { 45 std::sort(this->begin(), this->end()); 46 } else { 47 std::sort(this->begin(), this->end(), std::greater<int>()); 48 } 49 is_dirty = true; 50 } 51 52 int GradeCalc::min() const { 53 if(this->empty()) { 54 return -1; 55 } 56 return *std::min_element(this->begin(), this->end()); 57 } 58 59 int GradeCalc::max() const { 60 if(this->empty()) { 61 return -1; 62 } 63 return *std::max_element(this->begin(), this->end()); 64 } 65 66 double GradeCalc::average() const { 67 if(this->empty()) { 68 return 0.0; 69 } 70 double avg = std::accumulate(this->begin(), this->end(), 0.0) / this->size(); 71 return avg; 72 } 73 74 void GradeCalc::info() { 75 if(is_dirty) { 76 compute(); 77 } 78 // 输出课程名、平均分、最高分、最低分 79 std::cout << "课程名称:\t" << course_name << std::endl; 80 std::cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() << std::endl; 81 std::cout << "最高分:\t" << max() << std::endl; 82 std::cout << "最低分:\t" << min() << std::endl; 83 84 const std::array<std::string, 5> grade_range{"[0, 60) ", "[60, 70)", "[70, 80)", "[80, 90)", "[90, 100]"}; 85 for(int i = grade_range.size()-1; i >= 0; --i) { 86 std::cout << grade_range[i] << "\t: " << counts[i] << "人\t" 87 << std::fixed << std::setprecision(2) << rates[i]*100 << "%\n"; 88 } 89 } 90 91 void GradeCalc::compute() { 92 if(this->empty()) { // 无成绩时直接返回,避免无效计算 93 return; 94 } 95 counts.fill(0); // 重置分数段计数,避免历史数据干扰 96 rates.fill(0.0); // 重置分数段占比,避免历史数据干扰 97 98 for(int grade: *this) { 99 if(grade < 60) { 100 ++counts[0]; // [0,60) 对应索引0 101 } else if (grade < 70) { 102 ++counts[1]; // [60,70) 对应索引1 103 } else if (grade < 80) { 104 ++counts[2]; // [70,80) 对应索引2 105 } else if (grade < 90) { 106 ++counts[3]; // [80,90) 对应索引3 107 } else { 108 ++counts[4]; // [90,100] 对应索引4 109 } 110 } 111 112 for(int i = 0; i < rates.size(); ++i) { 113 rates[i] = counts[i] * 1.0 / this->size(); 114 } 115 116 is_dirty = false; 117 }
1 #pragma once 2 #include <array> 3 #include <string> 4 #include <vector> 5 6 class GradeCalc: private std::vector<int> { 7 public: 8 GradeCalc(const std::string &cname); 9 void input(int n); // 录入n个成绩 10 void output() const; // 输出成绩 11 void sort(bool ascending = false); // 排序 (默认降序) 12 int min() const; // 返回最低分 13 int max() const; // 返回最高分 14 double average() const; // 返回平均分 15 void info(); // 输出成绩统计信息 16 17 private: 18 void compute(); // 计算成绩统计信息 19 20 private: 21 std::string course_name; // 课程名 22 // 保存各分数段人数([0, 60), [60, 70), [70, 80), [80, 90), [90, 100] 23 std::array<int, 5> counts; 24 std::array<double, 5> rates; // 保存各分数段占比 25 bool is_dirty; // 脏标记,记录是否成绩信息有变更 26 };
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(); 16 c1.output(); 17 18 std::cout << "*************成绩统计信息*************\n"; 19 c1.info(); 20 } 21 22 int main() { 23 test(); 24 return 0; 25 }
运行结果:

问题:
1.class GradeCalc: private std::vector<int>
2.
不会自动成为接口;
不合法,无法编译。因为私有继承,push_back接口被隐藏,外部无法调用。
3.
组合:for(auto grade: grades),通过私有成员变量grades访问数据,封装性强,仅暴露类内定义的接口;
继承:for(int grade: *this),通过*this访问数据,直接用基类成员,封装性差。
4.组合更适合。理由:成绩计算核心是 “用vector存成绩”,仅暴露所需接口;继承易暴露不必要的基类接口,且不符合的逻辑关系。
test3:
源代码:
1 #pragma once 2 #include <string> 3 #include <vector> 4 5 enum class GraphType {circle, triangle, rectangle}; 6 7 class Graph { 8 public: 9 // 虚函数draw,供子类重写(原文档已有,补充函数体分号) 10 virtual void draw() {} 11 // 虚析构函数,确保子类对象正确析构(原文档已有) 12 virtual ~Graph() = default; 13 }; 14 15 // 圆形类,继承Graph(原文档已有,补充函数分号) 16 class Circle : public Graph { 17 public: 18 void draw() override; 19 }; 20 21 class Triangle : public Graph { 22 public: 23 void draw() override; 24 }; 25 26 class Rectangle : public Graph { 27 public: 28 void draw() override; 29 }; 30 31 class Canvas { 32 public: 33 void add(const std::string& type); // 根据字符串添加图形(原文档已有) 34 void paint() const; 35 ~Canvas(); 36 37 private: 38 std::vector<Graph*> graphs; 39 }; 40 41 // 工具函数声明(原文档已有,补充分号) 42 GraphType str_to_GraphType(const std::string& s); // 字符串转图形类型 43 Graph* make_graph(const std::string& type); // 创建图形,返回堆对象指针
1 #include <algorithm> 2 #include <cctype> 3 #include <iostream> 4 #include <string> 5 #include "Graph.hpp" 6 7 void Circle::draw() { 8 std::cout << "draw a circle...\n"; // 原文档指定输出内容 9 } 10 11 void Triangle::draw() { 12 std::cout << "draw a triangle...\n"; // 原文档指定输出内容 13 } 14 15 void Rectangle::draw() { 16 std::cout << "draw a rectangle...\n"; // 原文档指定输出内容 17 } 18 19 void Canvas::add(const std::string& type) { 20 Graph* g = make_graph(type); // 调用工具函数创建图形对象 21 if (g) { // 若创建成功,将图形指针加入容器 22 graphs.push_back(g); 23 } 24 } 25 26 void Canvas::paint() const { 27 for (Graph* g : graphs) { // 遍历所有图形指针 28 g->draw(); // 调用虚函数,实现多态绘制 29 } 30 } 31 32 Canvas::~Canvas() { 33 for (Graph* g : graphs) { // 遍历所有图形指针 34 delete g; // 释放单个图形对象 35 } 36 graphs.clear(); // 清空容器( 37 } 38 39 GraphType str_to_GraphType(const std::string& s) { 40 std::string t = s; 41 std::transform(s.begin(), s.end(), t.begin(), [](unsigned char c) { 42 return std::tolower(c); 43 }); 44 // 根据小写字符串匹配图形类型 45 if (t == "circle") { 46 return GraphType::circle; 47 } else if (t == "triangle") { 48 return GraphType::triangle; 49 } else if (t == "rectangle") { 50 return GraphType::rectangle; 51 } else { 52 return GraphType::circle; // 默认返回圆形 53 } 54 } 55 56 Graph* make_graph(const std::string& type) { 57 // 先将字符串转为图形类型 58 GraphType gt = str_to_GraphType(type); 59 // 根据类型创建对应子类对象,返回基类指针(多态) 60 switch (gt) { 61 case GraphType::circle: 62 return new Circle; 63 case GraphType::triangle: 64 return new Triangle; 65 case GraphType::rectangle: 66 return new Rectangle; 67 default: 68 return nullptr; // 未知类型返回空指针 69 } 70 }
1 #include <iostream> 2 #include <string> 3 #include "Graph.hpp" 4 5 void test() { 6 Canvas canvas; // 创建画布对象 7 8 canvas.add("circle"); 9 canvas.add("triangle"); 10 canvas.add("rectangle"); 11 12 std::cout << "开始绘制所有图形:\n"; 13 canvas.paint(); 14 } 15 16 int main() { 17 test(); // 调用测试函数 18 return 0; 19 }
运行结果:

问题:
1.
2.
1) 仅执行基类Graph::draw(),输出空,无法触发子类的绘制逻辑,多态失效。
2) 出现 “切片问题”:vector<Graph>存储基类对象,子类对象存入时丢失子类特有信息,调用draw仅执行基类逻辑,无法实现多态绘制。
3) 子类对象析构不完整:仅调用基类~Graph(),子类堆内存(若有)无法释放,导致内存泄漏。
4.
利:控制内存生命周期,适合动态创建的多态对象;
弊:易遗漏delete导致内存泄漏
test4:
源代码:
1 #include "LabubuToy.hpp" 2 #include <random> 3 4 // ------------------------------ LabubuMoodToy 实现 ------------------------------ 5 void LabubuMoodToy::showLabubuInfo() const { 6 std::cout << "【拉布布情绪互动玩具信息】\n"; 7 std::cout << "名称:" << name << "\n外观:" << appearance << "\n尺寸:" << size << "\n价格:" << price << "元\n"; 8 std::cout << "特异功能:识别你的情绪,用语音+灯光回应你~\n开心时回应示例:" << happyResponses[0] << "\n难过时回应示例:" << sadResponses[0] << "\n\n"; 9 } 10 11 void LabubuMoodToy::doLabubuSpecial() const { 12 std::random_device rd; 13 std::mt19937 gen(rd()); 14 int randIdx = std::uniform_int_distribution<>(0, happyResponses.size()-1)(gen); 15 16 std::cout << "[拉布布情绪互动] 正在识别你的情绪...\n"; 17 if (userMood == "happy") { 18 std::cout << "检测到你很开心!拉布布回应:" << happyResponses[randIdx] << "\n灯光变化:" << happyLight << "\n"; 19 } else if (userMood == "sad") { 20 std::cout << "检测到你有点难过...拉布布安慰:" << sadResponses[randIdx] << "\n灯光变化:" << sadLight << "\n"; 21 } else { 22 std::cout << "拉布布没听清情绪呢~给你放首小歌吧~\n灯光变化:彩虹色慢闪\n"; 23 } 24 } 25 26 // ------------------------------ LabubuProjectionToy 实现 ------------------------------ 27 void LabubuProjectionToy::showLabubuInfo() const { 28 std::cout << "【拉布布场景投影玩具信息】\n"; 29 std::cout << "名称:" << name << "\n外观:" << appearance << "\n尺寸:" << size << "\n价格:" << price << "元\n"; 30 std::cout << "投影有效距离:" << projectionDistance << "米\n可投射场景:"; 31 for (size_t i = 0; i < scenes.size(); ++i) std::cout << "[" << i+1 << "]" << scenes[i] << " "; 32 std::cout << "\n特异功能:投射拉布布专属场景,搭配沉浸式音效~\n\n"; 33 } 34 35 void LabubuProjectionToy::doLabubuSpecial() const { 36 if (selectedScene < 1 || selectedScene > scenes.size()) { 37 std::cout << "无效场景编号!请选择1-" << scenes.size() << "的场景~\n"; 38 return; 39 } 40 int idx = selectedScene - 1; 41 std::cout << "[拉布布场景投影] 正在投射:" << scenes[idx] << "\n场景音效:" << sceneSounds[idx] << "\n提示:请将拉布布朝向墙面,保持" << projectionDistance << "米距离~\n"; 42 } 43 44 // ------------------------------ LabubuMusicToy 实现 ------------------------------ 45 void LabubuMusicToy::showLabubuInfo() const { 46 std::cout << "【拉布布音乐创编玩具信息】\n"; 47 std::cout << "名称:" << name << "\n外观:" << appearance << "\n尺寸:" << size << "\n价格:" << price << "元\n"; 48 std::cout << "按键对应音符:"; 49 for (size_t i = 0; i < noteKeys.size(); ++i) std::cout << "[" << i+1 << "号键]" << noteKeys[i] << " "; 50 std::cout << "\n特异功能:按按键创编音乐,还能保存你的作品~\n最多可保存:" << maxSaveCount << "首创编音乐\n\n"; 51 } 52 53 void LabubuMusicToy::doLabubuSpecial() const { 54 std::cout << "[拉布布音乐创编] 正在播放你的创编旋律~\n旋律音符:"; 55 for (int key : keyPresses) { 56 if (key < 1 || key > noteKeys.size()) { std::cout << "[无效按键] "; continue; } 57 std::cout << noteKeys[key-1] << " "; 58 } 59 std::cout << "\n如需保存,长按拉布布的肚子按键即可~\n附赠拉布布主题曲:" << defaultMelody << "\n"; 60 }
1 #pragma once 2 #include <string> 3 #include <iostream> 4 #include <vector> 5 6 // 抽象基类:LabubuToy 7 class LabubuToy { 8 protected: 9 std::string name; // 玩具名称 10 std::string appearance; // 外观特征 11 std::string size; // 尺寸 12 double price; // 价格 13 14 public: 15 LabubuToy(const std::string& name_, const std::string& appearance_, 16 const std::string& size_, double price_) 17 : name(name_), appearance(appearance_), size(size_), price(price_) {} 18 19 virtual void showLabubuInfo() const = 0; 20 virtual void doLabubuSpecial() const = 0; 21 22 virtual ~LabubuToy() = default; 23 }; 24 25 // 子类1:LabubuMoodToy(情绪互动) 26 class LabubuMoodToy : public LabubuToy { 27 private: 28 std::vector<std::string> happyResponses; 29 std::vector<std::string> sadResponses; 30 std::string happyLight; 31 std::string sadLight; 32 mutable std::string userMood; 33 34 public: 35 LabubuMoodToy(const std::string& name_, const std::string& appearance_, 36 const std::string& size_, double price_, 37 const std::vector<std::string>& happyResp_, 38 const std::vector<std::string>& sadResp_, 39 const std::string& happyLt_, const std::string& sadLt_) 40 : LabubuToy(name_, appearance_, size_, price_), 41 happyResponses(happyResp_), sadResponses(sadResp_), 42 happyLight(happyLt_), sadLight(sadLt_), userMood("normal") {} 43 44 void setMood(const std::string& mood) const { userMood = mood; } 45 46 void showLabubuInfo() const override; 47 void doLabubuSpecial() const override; 48 }; 49 50 // 子类2:LabubuProjectionToy(场景投影) 51 class LabubuProjectionToy : public LabubuToy { 52 private: 53 std::vector<std::string> scenes; 54 std::vector<std::string> sceneSounds; 55 int projectionDistance; 56 mutable int selectedScene; 57 58 public: 59 LabubuProjectionToy(const std::string& name_, const std::string& appearance_, 60 const std::string& size_, double price_, 61 const std::vector<std::string>& scenes_, 62 const std::vector<std::string>& sounds_, 63 int projDist_) 64 : LabubuToy(name_, appearance_, size_, price_), 65 scenes(scenes_), sceneSounds(sounds_), 66 projectionDistance(projDist_), selectedScene(1) {} 67 68 void selectScene(int index) const { selectedScene = index; } 69 70 void showLabubuInfo() const override; 71 void doLabubuSpecial() const override; 72 }; 73 74 // 子类3:LabubuMusicToy(音乐创编) 75 class LabubuMusicToy : public LabubuToy { 76 private: 77 std::vector<std::string> noteKeys; 78 std::string defaultMelody; 79 int maxSaveCount; 80 mutable std::vector<int> keyPresses; 81 82 public: 83 LabubuMusicToy(const std::string& name_, const std::string& appearance_, 84 const std::string& size_, double price_, 85 const std::vector<std::string>& noteKeys_, 86 const std::string& defaultMel_, 87 int maxSave_) 88 : LabubuToy(name_, appearance_, size_, price_), 89 noteKeys(noteKeys_), defaultMelody(defaultMel_), 90 maxSaveCount(maxSave_), keyPresses({}) {} 91 92 void setKeyPresses(const std::vector<int>& keys) const { keyPresses = keys; } 93 94 void showLabubuInfo() const override; 95 void doLabubuSpecial() const override; 96 };
1 #include "LabubuToy.hpp" 2 #include <vector> 3 4 int main() { 5 std::vector<std::string> happyResp = {"哇~你开心我也超开心!我们一起拍手吧~", "今天天气真好,和你一起玩太快乐啦!"}; 6 std::vector<std::string> sadResp = {"别难过啦~我给你唱首小歌好不好?", "摸摸头~一切都会好起来的,我一直陪着你~"}; 7 LabubuToy* moodLabubu = new LabubuMoodToy( 8 "星空情绪拉布布", "紫色渐变毛发+星星翅膀+发光眼睛", 9 "25cm坐姿", 229.0, happyResp, sadResp, 10 "粉紫色闪烁", "暖黄色常亮" 11 ); 12 13 std::vector<std::string> scenes = {"拉布布森林派对(小动物跳舞)", "拉布布太空漫游(星球+飞船)", "拉布布海底探险(小鱼+珊瑚)"}; 14 std::vector<std::string> sceneSounds = {"欢快的手风琴声+小动物叫声", "太空电波声+飞船引擎声", "海浪声+水泡声+海豚叫声"}; 15 LabubuToy* projLabubu = new LabubuProjectionToy( 16 "太空投影拉布布", "银色金属质感+可旋转头部(投影口)", 17 "30cm站姿", 299.0, scenes, sceneSounds, 2 18 ); 19 20 std::vector<std::string> noteKeys = {"do(左耳键)", "re(右耳键)", "mi(左爪键)", "fa(右爪键)"}; 21 LabubuToy* musicLabubu = new LabubuMusicToy( 22 "音乐精灵拉布布", "粉色毛发+钢琴键图案肚皮+可按耳朵/爪子", 23 "20cm坐姿", 199.0, noteKeys, "do-re-mi-fa-mi-re-do(欢快版)", 5 24 ); 25 26 std::vector<LabubuToy*> labubuList = {moodLabubu, projLabubu, musicLabubu}; 27 std::cout << "==================== 拉布布玩具家族清单 ====================\n"; 28 for (size_t i = 0; i < labubuList.size(); ++i) { 29 std::cout << "[" << i+1 << "] "; 30 labubuList[i]->showLabubuInfo(); 31 } 32 33 std::cout << "==================== 体验拉布布特异功能 ====================\n"; 34 std::cout << "\n【1. 情绪互动拉布布】\n"; 35 dynamic_cast<LabubuMoodToy*>(moodLabubu)->setMood("sad"); 36 moodLabubu->doLabubuSpecial(); 37 38 std::cout << "\n【2. 场景投影拉布布】\n"; 39 dynamic_cast<LabubuProjectionToy*>(projLabubu)->selectScene(2); 40 projLabubu->doLabubuSpecial(); 41 42 std::cout << "\n【3. 音乐创编拉布布】\n"; 43 std::vector<int> keyPresses = {1, 4, 3}; 44 dynamic_cast<LabubuMusicToy*>(musicLabubu)->setKeyPresses(keyPresses); 45 musicLabubu->doLabubuSpecial(); 46 47 for (LabubuToy* toy : labubuList) { 48 delete toy; 49 } 50 51 return 0; 52 }
运行结果:

问题场景描述:某玩具厂商推出 “拉布布” 系列智能毛绒玩具,需满足用户 “情感陪伴(情绪互动)、场景体验(IP 场景投影)、创意互动(音乐创编)” 的差异化需求,同时要统一管理玩具的基础信息(名称、外观等),并支持批量展示信息、触发功能体验,覆盖 “生产信息管理 + 用户功能体验” 的全流程场景。
各类的关系以及理由:继承关系:LabubuToy基类与LabubuMoodToy等子类为public继承(is-a),理由是基类封装拉布布玩具的通用属性(名称、外观)与统一接口(展示信息、执行功能),子类重写接口实现差异化功能,既复用共性逻辑、降低冗余,又支持多态批量操作,符合 “新增玩具仅扩展子类” 的开闭原则;组合关系(若扩展LabubuSet套装类):LabubuSet通过vector<LabubuToy*>组合多个玩具(has-a),理由是套装需 “包含” 多款玩具实现批量管理,同时玩具生命周期可独立于套装,适配 “单卖 / 套装卖” 的业务场景,且解耦套装与具体玩具类型。
实验总结:test4在ai的帮助下写了一下午,头晕目眩,基类纯虚函数的接口与子类重写的接口不匹配的问题看破头都没找出来,前面三个实验围绕组合、继承、多态展开:对比成绩计算器的两种实现,明确组合适配 “部分 - 整体”、强封装,继承仅适 “一般 - 特殊”;借图形与玩具场景,掌握多态及组合多态协同价值;还关注脏标记、虚析构等细节,最终理解需依业务选设计模式,兼顾功能、性能与资源安全。好难好难
浙公网安备 33010602011771号