OOP-实验四

news/2025/11/26 10:28:29/文章来源:https://www.cnblogs.com/meiyingbao/p/19270861

实验任务一

源代码

GradeCalc.hpp

点击查看代码
#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;                          // 返回最低分(如成绩未录入,返回-1)int max() const;                          // 返回最高分 (如成绩未录入,返回-1)double average() const;                   // 返回平均分 (如成绩未录入,返回0.0)void info();                      // 输出课程成绩信息 private:void compute();     // 成绩统计private:std::string course_name;     // 课程名std::vector<int> grades;     // 课程成绩std::array<int, 5> counts;      // 保存各分数段人数([0, 60), [60, 70), [70, 80), [80, 90), [90, 100]std::array<double, 5> rates;    // 保存各分数段人数占比 bool is_dirty;      // 脏标记,记录是否成绩信息有变更
};

GradeCalc.cpp

点击查看代码
#include <algorithm>
#include <array>
#include <cstdlib>
#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";std::exit(1);}grades.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());elsestd::sort(grades.begin(), grades.end(), std::greater<int>());
}int GradeCalc::min() const {if(grades.empty())return -1;auto it = std::min_element(grades.begin(), grades.end());return *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::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 = static_cast<int>(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];        // [0, 60)else if (grade < 70)++counts[1];        // [60, 70)else if (grade < 80)++counts[2];        // [70, 80)else if (grade < 90)++counts[3];        // [80, 90)else++counts[4];        // [90, 100]}// 统计各分数段比例for(size_t i = 0; i < rates.size(); ++i)rates[i] = counts[i] * 1.0 / grades.size();is_dirty = false;  // 更新脏标记
}

task1.cpp

点击查看代码
#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";c1.sort(); c1.output();std::cout << "*************成绩统计信息*************\n";c1.info();}int main() {test();
}

运行结果

image

实验结论

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

答:std::string course_name;存储课程名称;std::vector<int> grades;存储学生成绩的容器;std::array<int, 5> counts;存储五个分数段([0,60)、[60,70)、[70,80)、[80,90)、[90,100])的学生人数;std::array<double, 5> rates;存储五个分数段的学生人数所占比例。

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

GradeCalc c("OOP");
c.inupt(5);
c.push_back(97);  // 合法吗?

答:不合法,类GradeCalc并没有提供push_back的接口;如果直接使用push_back,也会因为缺少输入值检查导致脏数据,并且is_dirty赃位也被污染了。

问题3:架构设计分析
当前设计方案中,compute在info模块中调用:
(1)连续打印3次统计信息,compute会被调用几次?标记is_dirty起到什么作用?

答:1次。is_dirty用来记录成绩是否有变化,是否需要重新计算,减少了重复计算的性能损耗

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

答:不用。可以在update_grade(index, new_grade)函数中将is_dirty置1,在输出时会调用compute的,不用重复调用。

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

答:在compute函数里加,在计算各分段后加入

if(!grades.empty()) {std::vector<int> sorted_grades = grades;std::sort(sorted_grades.begin(), sorted_grades.end());size_t n = sorted_grades.size();double median = 0.0;if(n % 2 == 1) {median = sorted_grades[n/2];} else {median = (sorted_grades[n/2 - 1] + sorted_grades[n/2]) / 2.0;}}

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

答:不能。去掉的话,在更新成绩之后再次计算的时候,会因为counts和rates数组没归零导致结果不正确

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

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

答:没影响

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

答:有影响;去掉reserve(n)会导致在输入成绩过程中,vector可能发生多次内存重新分配数据拷贝,增加运行时间开销。

实验任务二

源代码

GradeCalc.hpp

点击查看代码
#pragma once#include <array>
#include <string>
#include <vector>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::array<int, 5> counts;   // 保存各分数段人数([0, 60), [60, 70), [70, 80), [80, 90), [90, 100]std::array<double, 5> rates; // 保存各分数段占比bool is_dirty;      // 脏标记,记录是否成绩信息有变更
};

GradeCalc.cpp

点击查看代码
#include <algorithm>
#include <array>
#include <cstdlib>
#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";return;}this->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());elsestd::sort(this->begin(), this->end(), std::greater<int>());
}  int GradeCalc::min() const {if(this->empty())return -1;return *std::min_element(this->begin(), this->end());
}  int GradeCalc::max() const {if(this->empty())return -1;return *std::max_element(this->begin(), this->end());
}    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" << 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 = static_cast<int>(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);// 统计各分数段人数for(int grade: *this) {if(grade < 60)++counts[0];        // [0, 60)else if (grade < 70)++counts[1];        // [60, 70)else if (grade < 80)++counts[2];        // [70, 80)else if (grade < 90)++counts[3];        // [80, 90)else++counts[4];        // [90, 100]}// 统计各分数段比例for(size_t i = 0; i < rates.size(); ++i)rates[i] = counts[i] * 1.0 / this->size();is_dirty = false;
}

task2.cpp

点击查看代码
#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";c1.sort(); c1.output();std::cout << "*************成绩统计信息*************\n";c1.info();}int main() {test();
}

运行截图

image

实验结论

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

答:

class GradeCalc: private std::vector<int>

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

 GradeCalc c("OOP");c.input(5);c.push_back(97);  // 合法吗?

答:会;不能通过编译,GradeCalc作为vector派生类,会继承他的接口,但是这里是private继承,无法在类外使用vector的接口。

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

// 组合方式
for(auto grade: grades)  // 通过什么接口访问数据
// 略
// 继承方式
for(int grade: *this)    
// 略

答:组合方式通过类的数据成员grades直接访问,继承方式通过继承获得vector的所有功能,使用*this作为vector对象,即GradeCalc作为一个vector

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

答:组合。在这里GradeCalc与grade的成绩应该是has a的关系,即拥有,而不是is a的关系,逻辑结构上组合关系更加清晰。

实验任务三

源代码

Graph.hpp

点击查看代码
#pragma once#include <string>
#include <vector>enum class GraphType {circle, triangle, rectangle};// 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;          
};// 4. 工具函数
GraphType str_to_GraphType(const std::string& s);  // 字符串转枚举类型
Graph* make_graph(const std::string& type);  // 创建图形,返回堆对象指针

Graph.cpp

点击查看代码
#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();   
}Canvas::~Canvas() {for (Graph* g : graphs) delete g;
}// 工具函数实现
// 字符串 → 枚举转换
GraphType str_to_GraphType(const std::string& s) {std::string t = s;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;}
}

demo3.cpp

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

运行截图

image

实验结论

问题1:对象关系识别
(1)写出Graph.hpp中体现"组合"关系的成员声明代码行,并用一句话说明被组合对象的功能。
答:std::vector<Graph*> graphs;记录和管理画布上所有的图形对象指针。
(2)写出Graph.hpp中体现"继承"关系的类声明代码行。
答:class Circle : public Graph class Triangle : public Graphclass Rectangle : public Graph

问题2:多态机制观察
(1)Graph中的draw若未声明成虚函数,Canvas::paint()中g->draw()运行结果会有何不同?
答:如果Graph中的draw未声明成虚函数,Canvas::paint()中g->draw()将始终调用Graph基类的draw方法
(2)若Canvas类std::vector<Graph*>改成std::vector,会出现什么问题?
答:存储的是Graph副本,不是实际派生类对象,调用draw()时始终调用Graph::draw(),无法调用派生类的重写方法。
(3)若~Graph()未声明成虚函数,会带来什么问题?
答:会导致派生类对象的析构函数不被调用,造成资源泄漏;

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

  • 在枚举类型中添加star
  • 新增Star类声明(继承Graph)
  • 添加Star的draw方法实现

问题4:资源管理,观察make_graph函数和Canvas析构函数:
(1)make_graph返回的对象在什么地方被释放?
答:make_graph返回的对象在Canvas的析构函数中被释放。
(2)使用原始指针管理内存有何利弊?
答:可以精确控制对象的创建和销毁时机,但容易造成内存泄漏及悬空指针。

实验任务四

设计性实验:综合运用组合、继承、虚函数实现用一个接口尝试所有玩具特异功能。
具体要求如下:
设计毛绒玩具类Toy

  • 数据成员:玩具名称、玩具类型等(更多数据成员请自行调研、扩充设计)
  • 接口:特异功能等(更多函数成员请自行调研、扩充设计)
  • 设计玩具工厂类ToyFactory,包含一组毛绒玩具。
  • 接口:显示工厂所有玩具信息(名称、类型、特异功能等)
    编写测试模块、运行测试
    代码组织
    类声明保存在xx.hpp, 类实现保存在xx.cpp, 测试模块和主体代码保存在demo4.cpp
    说明
  1. 本任务是设计性实验任务,题目只给出最小化、粗略描述,具体请调研市面上电子毛绒玩具并基于个人创造力
    做细化和拓展设计,包括:
    (1)方案确定(组合/继承)
    (2)类的数据成员设计
    (3)函数成员设计(接口和私有工具等)
  2. 在实验结论中,提供你设计这个应用的问题描述、对象关系、源码、测试截图

问题描述

我们有一个玩具工厂系统,可以创建不同类型的玩具,并且每个玩具有自己的特性和行为。
设计一个面向对象的玩具工厂系统,可以创建不同类型的玩具(如会说话的熊、发光的兔子、跳舞的企鹅、唱歌的鸟)。
每个玩具都有名称、电池电量,并且可以显示信息、玩耍和充电。同时,工厂可以管理所有玩具,包括展示所有玩具、测试所有功能、充电和统计。

对象关系

基类:Toy
继承:TalkingBear (会说话的熊)、GlowingRabbit (发光的兔子)、DancingPenguin (跳舞的企鹅)、SingingBird (唱歌的鸟)
组合:ToyFactory

源代码

toy.hpp

点击查看代码
#include <string>
#include <vector>enum class ToyType {TalkingBear, GlowingRabbit, DancingPenguin, SingingBird};class Toy {
public:Toy(const std::string& name, const std::string& type);virtual ~Toy() = default;virtual void showInfo() const;virtual void play() const = 0;  std::string getName() const { return name; }std::string getType() const { return type; }int getBatteryLevel() const { return battery_level; }// 充电功能virtual void charge(int minutes);protected:std::string name;std::string type;int battery_level;  // 电池电量 0-100bool is_charged;    // 是否已充电
};// 会说话的熊
class TalkingBear : public Toy {
public:TalkingBear(const std::string& name);void play() const override;void setPhrase(const std::string& phrase);private:std::string phrase;
};// 发光兔子
class GlowingRabbit : public Toy {
public:GlowingRabbit(const std::string& name);void play() const override;void setColor(const std::string& color);void charge(int minutes) override;  // 特殊充电逻辑private:std::string light_color;int brightness;  // 亮度级别
};// 跳舞企鹅
class DancingPenguin : public Toy {
public:DancingPenguin(const std::string& name);void play() const override;void setDanceStyle(const std::string& style);private:std::string dance_style;int dance_duration;  // 舞蹈时长
};// 唱歌小鸟
class SingingBird : public Toy {
public:SingingBird(const std::string& name);void play() const override;void setSong(const std::string& song);private:std::string song;int volume;  // 音量级别
};class ToyFactory {
public:ToyFactory();~ToyFactory();void addToy(const std::string& type, const std::string& name);void showAllToys() const;void testAllFunctions() const;void chargeAllToys(int minutes);Toy* findToy(const std::string& name) const;void showStatistics() const;private:std::vector<Toy*> toys;int total_toys;
};// 4. 工具函数
ToyType str_to_ToyType(const std::string& s);  // 字符串转枚举类型
Toy* make_toy(const std::string& type, const std::string& name);  // 创建玩具,返回堆对象指针

toy.cpp

点击查看代码
#include "toy.hpp"
#include <iostream>
#include <algorithm>
#include <numeric>
#include <cctype>using namespace std;// 基类
Toy::Toy(const string& name_, const string& type_): name(name_), type(type_), battery_level(50), is_charged(false) {}void Toy::showInfo() const {cout << "类型: " << type << ", 名称: " << name<< ", 电量: " << battery_level << "%"<< ", 充电状态: " << (is_charged ? "是" : "否") << '\n';
}void Toy::charge(int minutes) {if (minutes <= 0) return;battery_level = min(100, battery_level + minutes);is_charged = (battery_level > 0);
}// TalkingBear
TalkingBear::TalkingBear(const string& name): Toy(name, "会说话的熊"), phrase("你好!") {}void TalkingBear::play() const {cout << "[会说话的熊] " << name << " 说: '" << phrase << "'\n";
}void TalkingBear::setPhrase(const string& p) {phrase = p;
}GlowingRabbit::GlowingRabbit(const string& name): Toy(name, "发光兔子"), light_color("白色"), brightness(5) {}void GlowingRabbit::play() const {cout << "[发光兔子] " << name << " 发光: " << light_color<< " , 亮度: " << brightness << "\n";
}void GlowingRabbit::setColor(const string& color) {light_color = color;
}void GlowingRabbit::charge(int minutes) {if (minutes <= 0) return;battery_level = min(100, battery_level + minutes * 2);brightness = min(10, brightness + minutes / 5);is_charged = (battery_level > 0);
}DancingPenguin::DancingPenguin(const string& name): Toy(name, "跳舞企鹅"), dance_style("华尔兹"), dance_duration(10) {}void DancingPenguin::play() const {cout << "[跳舞企鹅] " << name << " 跳舞 '" << dance_style<< "' 持续 " << dance_duration << " 秒" << "\n";
}void DancingPenguin::setDanceStyle(const string& style) {dance_style = style;
}SingingBird::SingingBird(const string& name): Toy(name, "唱歌小鸟"), song("啦啦"), volume(5) {}void SingingBird::play() const {cout << "[唱歌小鸟] " << name << " 唱歌 '" << song<< "' 音量 " << volume << "\n";
}void SingingBird::setSong(const string& s) {song = s;
}ToyFactory::ToyFactory() : total_toys(0) {}ToyFactory::~ToyFactory() {for (auto p : toys) delete p;toys.clear();
}void ToyFactory::addToy(const string& type, const string& name) {Toy* t = make_toy(type, name);if (t) {toys.push_back(t);++total_toys;}
}void ToyFactory::showAllToys() const {cout << "--- 所有玩具 ---\n";for (const auto& t : toys) {if (t) t->showInfo();}
}void ToyFactory::testAllFunctions() const {cout << "--- 测试所有玩具 ---\n";for (const auto& t : toys) {if (t) {t->showInfo();t->play();}}
}void ToyFactory::chargeAllToys(int minutes) {for (auto& t : toys) {if (t) t->charge(minutes);}
}Toy* ToyFactory::findToy(const string& name_) const {for (auto t : toys) {if (t && t->getName() == name_) return t;}return nullptr;
}void ToyFactory::showStatistics() const {cout << "--- 统计 ---\n";cout << "玩具总数: " << total_toys << "\n";if (toys.empty()) return;double avg = accumulate(toys.begin(), toys.end(), 0.0,[](double acc, Toy* t){ return acc + (t ? t->getBatteryLevel() : 0); }) / toys.size();cout << "平均电量: " << avg << "%\n";
}// Helpers
ToyType str_to_ToyType(const string& s) {string low;low.reserve(s.size());for (char c : s) low.push_back(tolower((unsigned char)c));if (low.find("talk") != string::npos || low.find("bear") != string::npos) return ToyType::TalkingBear;if (low.find("glow") != string::npos || low.find("rabbit") != string::npos) return ToyType::GlowingRabbit;if (low.find("dance") != string::npos || low.find("penguin") != string::npos) return ToyType::DancingPenguin;if (low.find("sing") != string::npos || low.find("bird") != string::npos) return ToyType::SingingBird;return ToyType::TalkingBear;
}Toy* make_toy(const string& type, const string& name) {switch (str_to_ToyType(type)) {case ToyType::TalkingBear: return new TalkingBear(name);case ToyType::GlowingRabbit: return new GlowingRabbit(name);case ToyType::DancingPenguin: return new DancingPenguin(name);case ToyType::SingingBird: return new SingingBird(name);}return nullptr;
}

demo4.cpp

点击查看代码
#include "toy.hpp"
#include <iostream>using namespace std;int main() {ToyFactory factory;factory.addToy("TalkingBear", "Ted");factory.addToy("GlowingRabbit", "Luna");factory.addToy("DancingPenguin", "Penny");factory.addToy("SingingBird", "Chirpy");cout << "初始化 玩具:\n";factory.showAllToys();cout << "\n玩所有玩具:\n";factory.testAllFunctions();// 定制部分:根据类型设置特有属性if (auto t = factory.findToy("Ted")) {if (auto bear = dynamic_cast<TalkingBear*>(t)) bear->setPhrase("我爱 C++!");}if (auto t = factory.findToy("Luna")) {if (auto rab = dynamic_cast<GlowingRabbit*>(t)) rab->setColor("紫色");}if (auto t = factory.findToy("Penny")) {if (auto pen = dynamic_cast<DancingPenguin*>(t)) pen->setDanceStyle("嘻哈");}if (auto t = factory.findToy("Chirpy")) {if (auto bird = dynamic_cast<SingingBird*>(t)) bird->setSong("小星星");}cout << "\n定制后:\n";factory.testAllFunctions();cout << "\n为所有玩具充电10分钟...\n";factory.chargeAllToys(10);factory.showAllToys();factory.showStatistics();return 0;
}

运行截图

image

实验总结

了解熟悉了virtual实现多态,体会到了组合和继承的适用场景以及该如何设计类对象,灵活使用组合继承关系和多态

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

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

相关文章

2025年LED灯珠优质厂家权威推荐榜单:LED灯‌/led灯‌/led景观灯‌源头厂家精选

在2025年LED照明行业持续发展的背景下,全球LED灯珠市场规模稳步增长,技术创新与专业化分工已成为推动行业发展的核心动力。 LED灯珠作为照明产品的核心部件,其性能直接决定终端产品的品质与寿命。当前,高光效、高显…

吴恩达深度学习课程三: 结构化机器学习项目 第一周:机器学习策略(二)数据集设置

此分类用于记录吴恩达深度学习课程的学习笔记。 课程相关信息链接如下:原课程视频链接:[双语字幕]吴恩达深度学习deeplearning.ai github课程资料,含课件与笔记:吴恩达深度学习教学资料 课程配套练习(中英)与答案…

分布式、域控及SOA架构车身功能测试方案

车身域是指负责管理和控制汽车车身相关功能的一个功能域,在汽车域控系统中起着至关重要的作用。它涵盖了车门、车窗、车灯、雨刮器等各种与车身相关的功能模块。与汽车电子电气架构升级相一致,车身域发展亦可以划分为…

2025年广东枫叶卡企业外派保卡豁免条件方案权威榜单:广东枫叶卡企业外派保卡审批/广东枫叶卡企业外派保卡进度查询渠道/广东枫叶卡企业外派保卡失败原因服务机构精选

面对加拿大永久居民卡的居住要求,众多企业外派人员通过人道主义与同情理由申请豁免,成功率高达95%的专业方案揭秘。 对于常驻广东的加拿大永久居民而言,企业外派任务往往与维持枫叶卡有效性形成矛盾。根据加拿大移民…

2025 年 11 月靶材厂家权威推荐榜:溅射/磁控溅射/镀膜/旋转靶材,ITO/半导体/光学镀膜/陶瓷/金属/钛/铝/铜/钨/钼/钽/硅/合金/稀土靶材精选品牌,技术实力与镀膜效果深度解析

2025 年 11 月靶材厂家权威推荐榜:溅射/磁控溅射/镀膜/旋转靶材,ITO/半导体/光学镀膜/陶瓷/金属/钛/铝/铜/钨/钼/钽/硅/合金/稀土靶材精选品牌,技术实力与镀膜效果深度解析 一、行业背景与发展趋势 靶材作为现代高端…

2025 年 11 月 CNC 加工中心厂家权威推荐榜:精密零件/五轴模具/高速龙门加工中心定制选型与编程技术深度解析

2025 年 11 月 CNC 加工中心厂家权威推荐榜:精密零件/五轴模具/高速龙门加工中心定制选型与编程技术深度解析 行业背景与发展趋势 随着制造业向智能化、精密化方向快速发展,CNC加工中心作为现代制造业的核心装备,其…

基于MATLAB GUI的AIS自动船舶系统显示实现

一、系统架构设计功能模块划分 数据接收模块:支持串口或网络接收AIS数据(NMEA格式)。 数据解析模块:解析MMSI、经纬度、航向、速度等关键字段。 地图显示模块:基于地理坐标动态展示船舶位置与航迹。 状态监控模块…

Java新手建站避坑:3天遭爬取后,10分钟部署免费WAF护住学习笔记

Java新手建站避坑:3天遭爬取后,10分钟部署免费WAF护住学习笔记逛博客园三年,去年终于下定决心搭了自己的技术博客,专门用来沉淀Java学习笔记。跟着园友的教程,用腾讯云学生机+宝塔面板装好了Typecho,第一篇《Spr…

2025年复式别墅定做厂家权威推荐榜单:活动房‌/苹果舱‌/集装箱房‌源头厂家精选

在2025年,模块化建筑已成为复式别墅领域的一股创新力量,以其施工速度快、设计个性化和环保可重复利用的特点,正改变着传统高端住宅的建造模式。 复式别墅定做行业在2025年正迎来高速发展期,活动房、苹果舱、集装箱…

2025天津留学机构推荐排名前十

2025天津留学机构推荐排名前十作为一名从业12年的国际教育规划师,我经常被天津的留学生和家长问及如何选择靠谱的留学中介。随着2025年留学申请季的临近,许多天津学生开始纠结:天津本地的留学中介哪家更值得信赖?申…

2025厦门比较好的留学机构有哪些

2025厦门比较好的留学机构有哪些一、厦门留学机构如何选择?这五大问题你考虑过吗?作为拥有八年国际教育规划经验的资深顾问,每天都会遇到厦门学生和家长提出各类择机构难题。通过分析2025年以来的搜索引擎数据,我发…

2025 最新推荐黄金麻实力厂家排行榜:涵盖全品类加工 + 出口级品质,助力工程采购精准选型黄金麻蘑菇石/黄金麻自然面/黄金麻地铺石/黄金麻火烧板/黄金麻地铺板/黄金麻仿古石公司推荐

引言 黄金麻作为高端建筑与园林装修的核心石材,凭借金黄质感与超强耐用性,广泛应用于外墙干挂、地铺装饰、路沿石铺设等场景。但当前市场中,无矿山企业原料品质难保障、小厂加工精度不足、色差超标、环保与辐射合规…

2025热门出国留学机构

2025热门出国留学机构一、 如何选择留学中介:五大高频问题帮你避坑作为一名从事国际教育规划工作超过十年的专业人士,我经常遇到学生和家长提出类似的问题:2025年留学市场这么卷,到底哪家中介更靠谱?申请美国研究…

2025北京留学机构哪家好

2025北京留学机构哪家好一、2025年北京留学机构如何选择?这五类问题你需要先想清楚2025年10月24日,随着海外院校申请季的来临,许多北京家庭又开始为选择留学机构而犯难。作为拥有8年国际教育规划经验的从业者,我每…

2025 年 11 月铝单板厂家权威推荐榜:氟碳铝单板、仿木纹铝单板、仿石材铝单板,精选耐用美观的定制化外墙装饰解决方案

2025 年 11 月铝单板厂家权威推荐榜:氟碳铝单板、仿木纹铝单板、仿石材铝单板,精选耐用美观的定制化外墙装饰解决方案 随着建筑装饰行业对材料性能和外观要求的不断提升,铝单板作为一种轻质、耐用且可高度定制的外墙…

2025 年 11 月管道更换服务实力厂家推荐榜:覆盖老旧破损/防腐耐高温/无损快速更换,自来水/燃气/暖气/工业/中央空调/地下室内外管道专业施工与高效解决方案

2025 年 11 月管道更换服务实力厂家推荐榜:覆盖老旧破损/防腐耐高温/无损快速更换,自来水/燃气/暖气/工业/中央空调/地下室内外管道专业施工与高效解决方案 管道系统作为基础设施的重要组成部分,其运行状态直接影响…

2025年一对一辅导机构口碑教师排行榜TOP10,一对一家教/上门家教一对一家教机构老师排行

行业背景分析 随着个性化教育需求的持续增长,一对一辅导市场呈现出蓬勃发展的态势。据最新教育行业数据显示,2024年一对一辅导市场规模已突破千亿元,预计2025年将保持15%以上的年增长率。在这一背景下,优质师资成为…

2025年最受欢迎的一对一家教老师TOP5,一对一家教/上门家教一对一家教机构老师推荐排行榜单

行业洞察 随着个性化教育需求的持续增长,一对一家教市场呈现出蓬勃发展的态势。据最新教育行业数据显示,2024年一对一辅导市场规模已达2850亿元,预计2025年将突破3000亿元大关。在众多教育机构中,以师资力量、教学…

[题解]P12444 [COTS 2025] 发好奖 / Hijerarhija

P12444 [COTS 2025] 发好奖 / Hijerarhija 和树上背包很像,唯一区别在于必须分配 \(c_i\) 的空间才能产生价值。 如果按普通的分组背包来跑,值域是 \(nk\) 的,总时间 \(O(nk^2)\) 过不掉。为此我们尽可能避免合并泛…

开源的 微信、QQ、TIM 防撤回补丁

开源的 微信、QQ、TIM 防撤回补丁适用于 Windows 下 PC 版微信/QQ/TIM的防撤回补丁 支持最新版微信/QQ/TIM 其中微信能够选择安装多开功01 使用方法02 说明 📌 使用注意事项(必看!)仅支持 Windows 7 及以上系统,…