实验4 组合与继承

实验任务1

运行结果截图如下

image

问题1

GradeCalc 类声明中,体现"组合"关系的成员声明及对应功能如下:

std::vector<int> grades;       grades用于存储所有成绩数据
std::array<int, 5> counts;     counts用于统计各分数段人数
std::array<double, 5> rates;    rates用于统计各分数段比例

 

问题2

首先要指出题目中把"input"拼成了"inupt"。

不合法。因为push_back() 是 std::vector 的方法,不是 GradeCalc 的公开接口。而grades 是私有成员,外部无法直接访问,故只能通过 GradeCalc 提供的 input() 方法添加成绩。

问题3

(1)compute连续打印3次,只调用1次。

is_dirty用来标记数据是否被修改,避免重复计算

(2)不需要更改compute调用位置。因为本来数据的变更就在计算前处理,新增后仍保持对数据统一计算。

问题4

可以在info()函数中插入一段

 

void GradeCalc::info() {
    if (is_dirty) compute();
    
    // ... 原有的输出代码 ...

    std::cout << "中位数:\t" << std::fixed << std::setprecision(2);
    
    if (grades.empty()) {
        std::cout << "0.00" << std::endl;
    } else {
        std::vector<int> temp = grades;
        std::sort(temp.begin(), temp.end());
        size_t n = temp.size();
        if (n % 2 == 1) {
            std::cout << static_cast<double>(temp[n / 2]) << std::endl;
        } else {
            std::cout << (temp[n / 2 - 1] + temp[n / 2]) / 2.0 << std::endl;
        }
    }
    
    // ... 继续原有的输出 ...
}

 

问题5

不能去掉。去掉就会导致数组无法正常初始化,统计结果会包含前一次的数据,多次调用compute()会导致数据累加。

问题6

功能上无影响;去掉后不会改变程序的功能,程序仍能正常运行且正常输入输出。

 

 

性能上有影响;因为去掉后push_back() 在自动分配内存以保证功能正常实现,这也意味着程序在反复扩充内存,进而影响性能。

实验任务2

运行结果截图如下

屏幕截图 2025-12-02 195058

问题1

class GradeCalc : private std::vector<int>

问题2

会,合法。能。当GradeCalc公有继承自std::vector<int>,则其继承了基类的所有公有接口,而push_back()是std::vector的公有方法。

问题3

封装差异:组合方式完全封装了底层容器,继承方式暴露了部分容器特性。

接口差异:组合方式必须提供自己的接口,继承方式可以直接使用基类接口。

问题4

选择组合。因为程序的功能是实现成绩计算器,其"有"成绩列表,不要求"是"列表,用组合的方式去写,可以直观地编写不同的类。同时用组合只暴露必要的接口,防止外部调用继承的私有函数。

实验任务3

运行结果截图如下

屏幕截图 2025-12-02 200601

问题1

(1)std::vector<Graph*> graphs;   存储图形的指针

(2)

class Circle : public Graph
class Triangle : public Graph
class Rectangle : public Graph

问题2

(1)g->draw() 只会调用基类的 draw()

结果输出"draw a...",无法实现多态

(2) 会导致派生类的特有信息丢失,只能存储基类部分。

(3) 派生类资源无法释放。

问题3

 

在GraphType枚举中添加star
在enum之后添加Star类声明
实现Star::draw()
修改str_to_GraphType函数

GraphType str_to_GraphType(const std::string& s) {
    if (s == "circle") return GraphType::circle;
    // ... 其他类型
    if (s == "star") return GraphType::star;
    throw std::invalid_argument("未知图形类型");
}

修改make_graph函数

Graph* make_graph(GraphType t) {
    switch(t) {
        case GraphType::circle: return new Circle();
        // ... 其他类型
        case GraphType::star: return new Star();
    }
}

问题4

(1) 在 Canvas 的析构函数中释放
(2)
利:简单直接,没有额外开销
弊:需要手动管理释放,易导致内存泄漏

 

实验任务4

源代码如下

toy.hpp

 

#ifndef TOY_HPP
#define TOY_HPP

#include <iostream>
#include <string>
#include <vector>

class Toy {
public:
    Toy(const std::string& name, const std::string& type, const std::string& color)
        : name(name), type(type), color(color) {}
    
    virtual ~Toy() = default;
    
    void displayInfo() const {
        std::cout << "玩具名称:" << name << std::endl;
        std::cout << "玩具类型:" << type << std::endl;
        std::cout << "玩具颜色:" << color << std::endl;
    }
    
    virtual void specialfunc() const = 0;

private:
    std::string name;
    std::string type;
    std::string color;
};

class FurinaDoll : public Toy {
public:
    FurinaDoll(const std::string& name, const std::string& color)
        : Toy(name, "Q版玩偶", color) {}
    
    void specialfunc() const override;
};

class MawikaDoll : public Toy {
public:
    MawikaDoll(const std::string& name, const std::string& color)
        : Toy(name, "解压玩具", color) {}
    
    void specialfunc() const override;
};

class ToyFactory {
public:
    ToyFactory() = default;
    ~ToyFactory() {
        for (auto toy : toystore) delete toy;
    }
    
    void addtoy(Toy* toy);
    void displayalltoys() const;

private:
    std::vector<Toy*> toystore;
};

#endif // TOY_HPP

 

toy.cpp

#include "toy.hpp"

void FurinaDoll::specialfunc() const {
    std::cout << "特异功能:录音 放音" << std::endl;
}

void MawikaDoll::specialfunc() const {
    std::cout << "特异功能:受到外力作用后能做出较大形变后复原" << std::endl;
}

void ToyFactory::addtoy(Toy* toy) {
    toystore.push_back(toy);
}

void ToyFactory::displayalltoys() const {
    for (const auto& toy : toystore) {
        toy->displayInfo();
        toy->specialfunc();
        std::cout << "---" << std::endl;
    }
}

main.cpp

#include "toy.hpp"

int main() {
    ToyFactory factory;
    
    factory.addtoy(new FurinaDoll("芙宁娜玩偶", ""));
    factory.addtoy(new FurinaDoll("芙宁娜玩偶", ""));
    factory.addtoy(new MawikaDoll("玛威卡人偶", ""));
    
    factory.displayalltoys();
    
    return 0;
}

运行结果截图如下

屏幕截图 2025-12-02 204344

总结

这次主要试验了组合和继承的设计的不同,虚函数实现多态。因为这种关联性,在编写时要格外注意细节。但是应用到实际从0编写的时候,容易迷失方向。在任务4里我花了很长时间才写出一个丐版的只有一个玩具类的程序(中途求助了一下我们班的学委),不过有了一个之后就很好类比着去扩写了。

 

posted @ 2025-12-02 20:51  勤垦原  阅读(3)  评论(0)    收藏  举报