实验4

实验任务1

GradeCalc.hpp

#pragma once
#include <vector>
#include <array>
#include <string>

class Gradecalc {
public:
    Gradecalc(const std::string &cname);
    void input(int n);
    void output() const;
    void sort(bool ascending = false);
    int  min() const;
    int  max() const;
    double average() const;
    void info();

private:
    void compute();
    std::string course_name;
    std::vector<int> grades;
    std::array<int, 5> counts{};
    std::array<double, 5> rates{};
    bool is_dirty;
};

GradeCalc.cpp

#include "GradeCalc.hpp"
#include <algorithm>
#include <numeric>
#include <iostream>
#include <iomanip>

Gradecalc::Gradecalc(const std::string &cname)
    : course_name(cname), is_dirty(true) { counts.fill(0); rates.fill(0.0); }

void Gradecalc::input(int n) {
    if (n <= 0) return;
    grades.reserve(n);
    int g;
    for (int i = 0; i < n; ) {
        std::cin >> g;
        if (g < 0 || g > 100) continue;
        grades.push_back(g); ++i;
    }
    is_dirty = true;
}

void Gradecalc::output() const {
    for (int g : grades) std::cout << g << ' ';
    std::cout << '\n';
}

void Gradecalc::sort(bool ascending) {
    std::sort(grades.begin(), grades.end(),
              ascending ? std::less<int>(): std::greater<int>());
    is_dirty = true;
}

int  Gradecalc::min() const {
    return grades.empty() ? -1 : *std::min_element(grades.begin(), grades.end());
}
int  Gradecalc::max() const {
    return grades.empty() ? -1 : *std::max_element(grades.begin(), grades.end());
}
double Gradecalc::average() const {
    return grades.empty() ? 0.0 :
           std::accumulate(grades.begin(), grades.end(), 0.0) / grades.size();
}

void Gradecalc::compute() {
    if (grades.empty()) return;
    counts.fill(0); rates.fill(0.0);
    for (int g : grades)
        ++counts[g < 60 ? 0 : g < 70 ? 1 : g < 80 ? 2 : g < 90 ? 3 : 4];
    for (int i = 0; i < 5; ++i) rates[i] = counts[i] * 1.0 / grades.size();
    is_dirty = false;
}

void Gradecalc::info() {
    if (is_dirty) compute();
    const std::array<std::string,5> R{"[0,60)","[60,70)","[70,80)","[80,90)","[90,100]"};
    std::cout << "课程: " << course_name << '\n'
              << "平均分: " << std::fixed << std::setprecision(2) << average() << '\n'
              << "最高分: " << max() << '\n'
              << "最低分: " << min() << '\n';
    for (int i = 4; i >= 0; --i)
        std::cout << R[i] << ' ' << counts[i] << "" << rates[i]*100 << "%\n";
}

demo1.cpp

#include "GradeCalc.hpp"
int main(){
    Gradecalc c("OOP");
    std::cout << "录入5个成绩:\n";
    c.input(5);
    std::cout << "输出:\n"; c.output();
    std::cout << "降序:\n"; c.sort(); c.output();
    std::cout << "统计:\n"; c.info();
}

image

 问题1:

std::vector<int> grades;:存储课程成绩; std::array<int,5> counts; :存储各分数段人数; std::array<double,5> rates; :存储各分数段比例

问题2:

不合法,grades是私有成员,类外无法直接访问

问题3(1):

只调用1次;避免重复计算

问题4:

不新增成员:在 info() 中加: auto tmp = grades;  std::sort(tmp.begin(), tmp.end());  double med = tmp[tmp.size()/2]; 。

问题5:

不能再次调用compute()时累加旧数据,导致错误

问题6:

无影响,性能上,导致多次扩容,降低效率

实验任务2

GradeCale.hpp

#pragma once
#include <vector>
#include <array>
#include <string>

class Gradecalc : private std::vector<int> {
public:
    explicit Gradecalc(const std::string &cname);
    void input(int n);
    void output() const;
    void sort(bool ascending = false);
    int  min() const;
    int  max() const;
    double average() const;
    void info();

private:
    void compute();
    std::string course_name;
    std::array<int,5> counts{};
    std::array<double,5> rates{};
    bool is_dirty;
};

GradeCale.cpp

#include "GradeCalc.hpp"
#include <algorithm>
#include <numeric>
#include <iostream>
#include <iomanip>

Gradecalc::Gradecalc(const std::string &cname)
    : course_name(cname), is_dirty(true) { counts.fill(0); rates.fill(0.0); }

void Gradecalc::input(int n) {
    if (n <= 0) return;
    this->reserve(n);
    int g;
    for (int i = 0; i < n; ) {
        std::cin >> g;
        if (g < 0 || g > 100) continue;
        this->push_back(g); ++i;
    }
    is_dirty = true;
}

void Gradecalc::output() const {
    for (int g : *this) std::cout << g << ' ';
    std::cout << '\n';
}

void Gradecalc::sort(bool ascending) {
    std::sort(this->begin(), this->end(),
              ascending ? std::less<int>(): std::greater<int>());
    is_dirty = true;
}

int  Gradecalc::min() const {
    return this->empty() ? -1 : *std::min_element(this->begin(), this->end());
}
int  Gradecalc::max() const {
    return this->empty() ? -1 : *std::max_element(this->begin(), this->end());
}
double Gradecalc::average() const {
    return this->empty() ? 0.0 :
           std::accumulate(this->begin(), this->end(), 0.0) / this->size();
}

void Gradecalc::compute() {
    if (this->empty()) return;
    counts.fill(0); rates.fill(0.0);
    for (int g : *this)
        ++counts[g < 60 ? 0 : g < 70 ? 1 : g < 80 ? 2 : g < 90 ? 3 : 4];
    for (int i = 0; i < 5; ++i) rates[i] = counts[i] * 1.0 / this->size();
    is_dirty = false;
}

void Gradecalc::info() {
    if (is_dirty) compute();
    const std::array<std::string,5> R{"[0,60)","[60,70)","[70,80)","[80,90)","[90,100]"};
    std::cout << "课程: " << course_name << '\n'
              << "平均分: " << std::fixed << std::setprecision(2) << average() << '\n'
              << "最高分: " << max() << '\n'
              << "最低分: " << min() << '\n';
    for (int i = 4; i >= 0; --i)
        std::cout << R[i] << ' ' << counts[i] << "" << rates[i]*100 << "%\n";
}

demo2.cpp

#include "GradeCalc.hpp"
int main(){
    Gradecalc c("OOP");
    std::cout << "录入5个成绩:\n";
    c.input(5);
    std::cout << "输出:\n"; c.output();
    std::cout << "降序:\n"; c.sort(); c.output();
    std::cout << "统计:\n"; c.info();
}

image

问题1:

class Gradecalc : private std::vector<int>

问题2:

合法,公有接口,类内可见

问题3:

第一个通过成员变量名访问

第二个通过自身作为容器访问

问题4:

组合更合适,成绩计算器是包含一个成绩容器,组合更清晰,封装性更强

实验任务3:

Graph.hpp

#pragma once
#include <vector>
#include <string>

enum class GraphType { circle, triangle, rectangle };

class Graph {
public:
    virtual void draw() const = 0;
    virtual ~Graph() = default;
};

class Circle : public Graph {
public:
    void draw() const override;
};
class Triangle : public Graph {
public:
    void draw() const override;
};
class Rectangle : public Graph {
public:
    void draw() const override;
};

class Canvas {
public:
    void add(const std::string& type);
    void paint() const;
    ~Canvas();
private:
    std::vector<Graph*> graphs;
};

Graph* make_graph(const std::string& type);

Graph.cpp

#include "Graph.hpp"
#include <algorithm>
#include <cctype>
#include <iostream>

void Circle::draw() const   { std::cout << "draw a circle\n"; }
void Triangle::draw() const { std::cout << "draw a triangle\n"; }
void Rectangle::draw() const{ std::cout << "draw a rectangle\n"; }

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;
}

static GraphType str_to_type(const std::string& s) {
    std::string t = s;
    std::transform(t.begin(), t.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; // default
}

Graph* make_graph(const std::string& type) {
    switch (str_to_type(type)) {
    case GraphType::circle:   return new Circle;
    case GraphType::triangle: return new Triangle;
    case GraphType::rectangle:return new Rectangle;
    }
    return nullptr;
}

demo3.cpp

#include "Graph.hpp"
int main(){
    Canvas canvas;
    canvas.add("circle");
    canvas.add("triangle");
    canvas.add("rectangle");
    canvas.paint();
}

image

 问题1(1):

std::vector<Graph*> graphs;:统一管理所有图形指针。

(2):

class Circle : public Graph

问题2(1):

无法多态,输出相同

(2):

会切片,丢失派生类信息

(3):
删除派生类对象时,派生类部分未析构,内存泄漏

问题3:
① Graph.hpp :新增 class Star : public Graph ;② Graph.cpp :实现 Star::draw() ;③ str_to_GraphType 加"star"分支;④ make_graph 中加case。

问题4(1):

在delete g;释放

(2):

灵活但是易漏删,写错

实验任务4:

Toy.hpp:

#pragma once
#include <memory>
#include <vector>
#include <string>

class Toy {
public:
    explicit Toy(std::string name) : toy_name(std::move(name)) {}
    virtual void specialFunction() const = 0;
    virtual ~Toy() = default;
    const std::string& name() const { return toy_name; }
private:
    std::string toy_name;
};

class Bear : public Toy {
public:
    Bear() : Toy("Bear") {}
    void specialFunction() const override;
};

class Bunny : public Toy {
public:
    Bunny() : Toy("Bunny") {}
    void specialFunction() const override;
};

class ToyFactory {
public:
    void add(std::unique_ptr<Toy> t) { toys.push_back(std::move(t)); }
    void showAll() const;
private:
    std::vector<std::unique_ptr<Toy>> toys;
};

Toy.cpp

#include "Toy.hpp"
#include <iostream>

void Bear::specialFunction() const {
    std::cout << name() << ": plays lullaby & glows in the dark\n";
}
void Bunny::specialFunction() const {
    std::cout << name() << ": hops and plays Easter song\n";
}

void ToyFactory::showAll() const {
    for (const auto& t : toys) t->specialFunction();
}

demo4:

#include "Toy.hpp"
int main(){
    ToyFactory f;
    f.add(std::make_unique<Bear>());
    f.add(std::make_unique<Bunny>());
    f.showAll();
}

image

 

posted @ 2025-12-03 00:26  15468483  阅读(0)  评论(0)    收藏  举报