Skip to content

信息学实验室作业(一)

更新: 2025/3/15 字数: 0 字 时长: 0 分钟

一、类结构设计

1. 基类 Vehicle

  • 成员变量
    • totalDistance:总行驶距离
    • totalTime:总使用时间
    • baseSpeed:基础速度
    • nameCString:交通工具名称
  • 核心方法
    • MakeTrip(double):纯虚函数,子类需实现行程逻辑。
    • GetSpeed():纯虚函数,子类需实现速度计算。
    • 比较运算符 <:默认按当前速度比较。

2. 子类 Aeroplane(飞机)

  • 特殊属性
    • timeSinceLastRepair:上次维修后的飞行时间。
    • 内部类 Computer:模拟机载计算机,记录启动时间。
  • 行为特性
    • 速度恒定(baseSpeed)。
    • 每次行程会增加飞行时间,超过 MAX_FLY_TIME 则无法飞行。
    • 维修后重置飞行时间 (Repair())。
    • 可更新计算机启动时间 (ComputerUpdate())。

3. 子类 Coach(马车)

  • 行为特性
    • 速度随时间指数衰减:speed = baseSpeed * exp(-totalTime/500)
    • 单次行程距离超过 MAX_DISTANCE 则无法行驶。

4. 子类 Automobile(汽车)

  • 行为特性
    • 速度随行驶距离指数衰减:speed = baseSpeed * exp(-totalDistance/500)
    • 无最大行程限制。

二、关键函数

1. 随机行程 CommitRandomTrips

  • 为所有交通工具生成随机距离(0-2000)的行程。
  • 调用 MakeTrip() 执行行程,不同交通工具可能失败(如飞机超时、马车超距)。

2. 显示信息 DisplayVehicles

  • 格式化输出交通工具的名称(附加英文类型)、当前速度、总距离和总时间。

  • 示例输出:

    名称(Name)          当前速度(Speed) 总行驶距离(Dist) 总使用时间(Time)  
    马车1(Coach)        9.0             500              55.5556

3. 排序算法

  • 选择排序 SelectionSort插入排序 InsertionSort
    • 支持自定义比较函数(如按速度或总时间排序)。
    • 模板化实现,适用于任意数据类型。
  • 比较函数
    • CompareDefault:按当前速度比较。
    • CompareTime:按总使用时间比较。

4. 维修飞机 FindAndRepairMaxFlightTimeAeroplane

  • 遍历所有交通工具,找到飞行时间最长的飞机并维修(重置飞行时间)。

三、主程序流程

1. 初始化对象

  • 创建5辆马车、4辆汽车、3架飞机,存入对应的 vector
  • 将所有对象的指针收集到 vehiclePointers 中。

2. 初始状态输出

cpp
cout << "初始交通工具信息(Initial Vehicles):" << endl;
DisplayVehicles(vehiclePointers);

3. 执行随机行程

cpp
CommitRandomTrips(vehiclePointers);

4. 排序与输出

  • 按默认速度排序(选择排序)。
  • 按插入排序再次排序。
  • 每次排序后输出结果。

5. 维修飞机并输出

cpp
FindAndRepairMaxFlightTimeAeroplane(vehiclePointers);

四、核心特性

1. 多态与继承

  • 通过基类指针调用 MakeTrip()GetSpeed(),实际执行子类实现。
  • 动态类型转换 (dynamic_cast) 用于识别飞机对象。

2. 速度衰减模型

  • 马车:速度随时间指数衰减(exp(-totalTime/500))。
  • 汽车:速度随距离指数衰减(exp(-totalDistance/500))。

3. 异常处理

  • 飞机的 MakeTrip() 返回 false 若超时,需维修后才能继续飞行。
  • 马车的 MakeTrip() 返回 false 若单次距离超过 MAX_DISTANCE

五、潜在改进点

1. 名称处理

  • 当前通过名称中的中文字符判断类型(如“马车”),不够健壮。可改为使用类型标识符(如枚举)。

2. 内存管理

  • vehiclePointers 存储的是局部对象的指针,若对象生命周期结束会导致悬空指针。此处因对象在主函数内创建,无问题,但需注意扩展性。

3. 排序性能

  • 对于大规模数据,选择排序和插入排序效率较低,可考虑更高效算法(如快速排序)。

六、需求回顾与完成情况检查

文档要求完成的任务主要包含以下几个方面,下面对各项任务的完成情况进行逐一检查:

1. 类的实现与测试

  • 任务内容:实现 Vehicle(交通工具)基类和 Aeroplane(飞机)、Coach(马车)、Automobile(汽车)等具体交通工具类。Vehicle 类包含抽象方法,具体类需重写这些方法。使用 CommitRandomTrips 函数对这些类进行测试,在 main 函数中初始化随机数生成器。
  • 完成情况
    • 代码中实现了 Vehicle 基类,包含抽象方法 MakeTripGetSpeed
    • 实现了 AeroplaneCoachAutomobile 类,并且重写了基类的抽象方法。
    • main 函数中使用 srand(0) 初始化了随机数生成器,同时调用 CommitRandomTrips 函数对交通工具对象进行了随机行程测试。所以该任务已完成。

2. 信息管理与输出

  • 任务内容:实现输入交通工具实例信息到对应数组的功能,并组织信息输出。输出方式包括按速度顺序从每个数组依次输出、按当前速度以统一列表输出、按输入顺序输出。可使用选择排序模板算法对数组指针进行排序,也可自定义比较函数。
  • 完成情况
    • 代码中创建了存储不同交通工具对象的 vector,并将对象指针存储在相应的指针 vector 中。
    • 实现了 DisplayVehicles 函数用于输出交通工具信息。
    • 使用选择排序模板 SelectionSort 对交通工具指针数组按速度进行了排序并输出。
    • 还实现了插入排序模板 InsertionSort 对交通工具指针数组按速度进行排序并输出。所以该任务已完成。

3. 完成拓展任务并再次测试

  • 任务内容:从五个任务变体中任选其一完成并再次测试程序。变体 1 要求实现插入排序模板;变体 2 需在随机移动后找到上次维修后飞行时间最长的飞机并维修;变体 3 要基于汽车类派生电动汽车和汽油汽车类并添加相关属性;变体 4 实现多重继承的“汽车拖车”类;变体 5 为不同交通工具实现不同的价格计算算法。
  • 完成情况
    • 实现了变体 1,即插入排序模板 InsertionSort
    • 实现了变体 2,即 FindAndRepairMaxFlightTimeAeroplane 函数,用于找到上次维修后飞行时间最长的飞机并维修。所以该任务已完成。

4. 绘制类图

  • 任务内容:完成上述任务后,绘制最终的类图,展示类之间的继承关系、属性和方法等。
  • 完成情况
    • 提供了使用 Mermaid 语法绘制的类图,清晰展示了 VehicleAeroplaneCoachAutomobile 类之间的继承关系,以及类的属性和方法,还展示了 Aeroplane 类与其内部类 Computer 的组合关系。所以该任务已完成。

全部代码展示

通过对各项任务的检查,代码已完成了文档中要求的所有内容。不仅实现了基本的类和测试,完成了信息管理与输出,还完成了拓展任务中的两个变体,并绘制了相应的类图。

c++
//
//  main.cpp
//  Demo
//
//  Created by 叶蓝骅 on 2025/2/28.
//

##include <iostream>
##include <stdlib.h>
##include <vector>
##include <cmath>
##include <iomanip>

using namespace std;

// 定义默认常量
const char DefaultVehicleName[] = "Untyped vehicle";
const char DefaultCoachName[] = "Default Coach";
const char DefaultAutomobileName[] = "Default Automobile";
const char DefaultAeroplaneName[] = "Default Aeroplane";
const double DefaultVehicleSpeed = -1.;
const double DefaultCoachSpeed = 10.;
const double DefaultAutomobileSpeed = 100.;
const double DefaultAeroplaneSpeed = 500.;
const double DefaultTimeToBoot = 0.01;

// 定义最大飞行时间和最大行驶距离
const double MAX_FLY_TIME = 100.;
const double MAX_DISTANCE = 500.;

// 定义交通工具基类
class Vehicle {
public:
    // 构造函数
    Vehicle() : totalDistance(0), totalTime(0), baseSpeed(DefaultVehicleSpeed) {
        SetName(DefaultVehicleName);
    }
    Vehicle(const char inNameCString[], double inBaseSpeed, int inBasePrice) : totalDistance(0), totalTime(0), baseSpeed(inBaseSpeed) {
        SetName(inNameCString);
    }
    // 析构函数
    virtual ~Vehicle() {}

    // 获取交通工具名称
    const char* const GetName() const {
        return nameCString;
    }
    // 获取购买时的速度
    double GetBaseSpeed() const {
        return baseSpeed;
    }
    // 获取总行驶距离
    double GetTotalDistance() const {
        return totalDistance;
    }
    // 获取总使用时间
    double GetTotalTime() const {
        return totalTime;
    }
    // 抽象方法:进行行程
    virtual bool MakeTrip(double distance) = 0;
    // 抽象方法:获取当前速度
    virtual double GetSpeed() const = 0;
    // 默认比较运算符
    bool operator<(Vehicle& rhs) const {
        if (GetSpeed() < rhs.GetSpeed()) {
            return true;
        }
        return false;
    }
protected:
    // 设置交通工具名称
    void SetName(const char inNameCString[]) {
        int i = 0;
        for (i = 0; (inNameCString[i] != 0) && (i < MAX_NAME_LENGTH); ++i) {
            nameCString[i] = inNameCString[i];
        }
        nameCString[i] = 0;
    }
    // 总行驶距离
    double totalDistance;
    // 总使用时间
    double totalTime;
    // 新交通工具的速度
    double baseSpeed;
private:
    // 存储交通工具名称的C字符串
    static const int MAX_NAME_LENGTH = 50;
    char nameCString[MAX_NAME_LENGTH];
};

// 定义飞机类
class Aeroplane : public Vehicle {
public:
    // 构造函数
    Aeroplane(const char inNameCString[], double inBaseSpeed) : Vehicle(inNameCString, inBaseSpeed, 0), timeSinceLastRepair(0) {}

    // 获取当前速度
    virtual double GetSpeed() const override {
        return GetBaseSpeed();
    }
    // 进行行程
    virtual bool MakeTrip(double distanceOfTrip) override {
        double timeOfTrip = distanceOfTrip / GetSpeed() + computer.GetTimeToBoot();
        if (timeSinceLastRepair + timeOfTrip > MAX_FLY_TIME) {
            return false;
        }
        timeSinceLastRepair += timeOfTrip;
        totalDistance += distanceOfTrip;
        totalTime += timeOfTrip;
        return true;
    }
    // 维修飞机
    void Repair() {
        timeSinceLastRepair = 0;
    }
    // 获取上次维修后的时间
    double GetTimeSinceLastRepair() const {
        return timeSinceLastRepair;
    }
    // 更新机载计算机
    void ComputerUpdate(double newTimeToBoot) {
        computer.SetTimeToBoot(newTimeToBoot);
    }
private:
    // 上次维修后的时间
    double timeSinceLastRepair;
    // 机载计算机
    class Computer {
    public:
        Computer() : baseTimeToBoot(DefaultTimeToBoot) {}
        double GetTimeToBoot() {
            return baseTimeToBoot;
        }
        void SetTimeToBoot(double newTime) {
            baseTimeToBoot = newTime;
        }
    protected:
        double baseTimeToBoot;
    } computer;
};

// 定义马车类
class Coach : public Vehicle {
public:
    // 构造函数
    Coach(const char inNameCString[], double inBaseSpeed = DefaultCoachSpeed) : Vehicle(inNameCString, inBaseSpeed, 0) {}

    // 获取当前速度
    virtual double GetSpeed() const override {
        return GetBaseSpeed() * exp(-totalTime / 500.);
    }
    // 进行行程
    virtual bool MakeTrip(double distanceOfTrip) override {
        if (distanceOfTrip > MAX_DISTANCE) {
            return false;
        }
        totalDistance += distanceOfTrip;
        totalTime += distanceOfTrip / GetSpeed();
        return true;
    }
};

// 定义汽车类
class Automobile : public Vehicle {
public:
    // 构造函数
    Automobile(const char inNameCString[], double inBaseSpeed = DefaultAutomobileSpeed) : Vehicle(inNameCString, inBaseSpeed, 0) {}

    // 获取当前速度
    virtual double GetSpeed() const override {
        return GetBaseSpeed() * exp(-totalDistance / 500.);
    }
    // 进行行程
    virtual bool MakeTrip(double distanceOfTrip) override {
        totalDistance += distanceOfTrip;
        totalTime += distanceOfTrip / GetSpeed();
        return true;
    }
};

// 随机行程函数
void CommitRandomTrips(vector<Vehicle*>& vehicles) {
    for (int i = 0; i < vehicles.size(); ++i) {
        double randomDistance = double(rand() % 20001) / 10.;
        vehicles[i]->MakeTrip(randomDistance);
    }
}

// 显示交通工具信息函数
void DisplayVehicles(const vector<Vehicle*>& vehicles) {
    // 输出表头,设置每列宽度
    cout << setw(25) << left << "名称(Name)"
         << setw(15) << "当前速度(Speed)"
         << setw(15) << "总行驶距离(Dist)"
         << setw(15) << "总使用时间(Time)" << endl;
    for (int i = 0; i < vehicles.size(); ++i) {
        const char* name = vehicles[i]->GetName();
        string nameWithEnglish;
        if (strstr(name, "马车") != nullptr) {
            nameWithEnglish = string(name) + "(Coach)";
        } else if (strstr(name, "汽车") != nullptr) {
            nameWithEnglish = string(name) + "(Automobile)";
        } else if (strstr(name, "飞机") != nullptr) {
            nameWithEnglish = string(name) + "(Aeroplane)";
        }
        // 输出每行数据,设置每列宽度
        cout << setw(25) << left << nameWithEnglish
             << setw(15) << vehicles[i]->GetSpeed()
             << setw(15) << vehicles[i]->GetTotalDistance()
             << setw(15) << vehicles[i]->GetTotalTime() << endl;
    }
}

// 选择排序模板
template <class MyType>
void MySwap(MyType& v1, MyType& v2) {
    MyType v3 = v1;
    v1 = v2;
    v2 = v3;
}

template <class ArrayType, class LessFunctionType>
int FindMinimumIndex(ArrayType& data_array, int beginIndex, int endIndex, LessFunctionType LessFunction) {
    int minimumIndex = beginIndex;
    for (int element_number = beginIndex + 1; element_number <= endIndex; ++element_number) {
        if (LessFunction(data_array[element_number], data_array[minimumIndex])) {
            minimumIndex = element_number;
        }
    }
    return minimumIndex;
}

template <class ArrayType, class LessFunctionType>
void SelectionSort(ArrayType& data_array, int beginIndex, int endIndex, LessFunctionType LessFunction) {
    for (int element_number = beginIndex; element_number < endIndex; ++element_number) {
        int minimumIndex = FindMinimumIndex(data_array, element_number, endIndex, LessFunction);
        MySwap(data_array[minimumIndex], data_array[element_number]);
    }
}

// 自定义比较函数
bool CompareDefault(Vehicle* lhs, Vehicle* rhs) {
    return *lhs < *rhs;
}

bool CompareTime(Vehicle* lhs, Vehicle* rhs) {
    return lhs->GetTotalTime() < rhs->GetTotalTime();
}

// 插入排序模板(实现变体1)
template <class ArrayType, class LessFunctionType>
void InsertionSort(ArrayType& data_array, int beginIndex, int endIndex, LessFunctionType LessFunction) {
    for (int i = beginIndex + 1; i <= endIndex; ++i) {
        typename ArrayType::value_type key = data_array[i];
        int j = i - 1;
        while (j >= beginIndex && LessFunction(key, data_array[j])) {
            data_array[j + 1] = data_array[j];
            --j;
        }
        data_array[j + 1] = key;
    }
}

// 找到上次维修后飞行时间最长的飞机并维修(实现变体2)
void FindAndRepairMaxFlightTimeAeroplane(vector<Vehicle*>& vehicles) {
    double maxTime = 0;
    Aeroplane* maxAeroplane = nullptr;
    for (int i = 0; i < vehicles.size(); ++i) {
        Aeroplane* aeroplane = dynamic_cast<Aeroplane*>(vehicles[i]);
        if (aeroplane) {
            double time = aeroplane->GetTimeSinceLastRepair();
            if (time > maxTime) {
                maxTime = time;
                maxAeroplane = aeroplane;
            }
        }
    }
    if (maxAeroplane) {
        maxAeroplane->Repair();
    }
}

int main() {
    srand(0);

    // 定义存储交通工具实例的向量
    vector<Coach> coaches;
    vector<Automobile> automobiles;
    vector<Aeroplane> aeroplanes;

    // 添加具体对象
    coaches.emplace_back("马车1", 9.);
    coaches.emplace_back("马车2", 11.);
    coaches.emplace_back("马车3", 10.);
    coaches.emplace_back("马车4", 9.5);
    coaches.emplace_back("马车5");

    automobiles.emplace_back("汽车1");
    automobiles.emplace_back("汽车2", 90.);
    automobiles.emplace_back("汽车3", 120.);
    automobiles.emplace_back("汽车4", 150.);

    aeroplanes.emplace_back("飞机1", 1030.);
    aeroplanes.emplace_back("飞机2", 560.);
    aeroplanes.emplace_back("飞机3", 2200.);

    // 定义存储交通工具指针的向量
    vector<Vehicle*> coachPointers;
    vector<Vehicle*> automobilePointers;
    vector<Vehicle*> aeroplanePointers;

    // 初始化指针向量
    for (int i = 0; i < coaches.size(); ++i) {
        coachPointers.push_back(&coaches[i]);
    }
    for (int i = 0; i < automobiles.size(); ++i) {
        automobilePointers.push_back(&automobiles[i]);
    }
    for (int i = 0; i < aeroplanes.size(); ++i) {
        aeroplanePointers.push_back(&aeroplanes[i]);
    }

    vector<Vehicle*> vehiclePointers;
    vehiclePointers.insert(vehiclePointers.end(), coachPointers.begin(), coachPointers.end());
    vehiclePointers.insert(vehiclePointers.end(), automobilePointers.begin(), automobilePointers.end());
    vehiclePointers.insert(vehiclePointers.end(), aeroplanePointers.begin(), aeroplanePointers.end());

    // 显示初始信息
    cout << "初始交通工具信息(Initial Vehicles):" << endl;
    DisplayVehicles(vehiclePointers);

    // 进行随机行程
    CommitRandomTrips(vehiclePointers);

    // 显示行程后的信息
    cout << "\n随机行程后的交通工具信息(Vehicles after random trips):" << endl;
    DisplayVehicles(vehiclePointers);

    // 选择排序并显示(按默认比较)
    SelectionSort(vehiclePointers, 0, static_cast<int>(vehiclePointers.size() - 1), CompareDefault);
    cout << "\n按默认比较排序后的交通工具信息(Vehicles sorted by default comparison):" << endl;
    DisplayVehicles(vehiclePointers);

    // 插入排序并显示(按默认比较,变体1)
    InsertionSort(vehiclePointers, 0, static_cast<int>(vehiclePointers.size() - 1), CompareDefault);
    cout << "\n按插入排序后的交通工具信息(Vehicles sorted by insertion sort):" << endl;
    DisplayVehicles(vehiclePointers);

    // 找到上次维修后飞行时间最长的飞机并维修(变体2)
    FindAndRepairMaxFlightTimeAeroplane(vehiclePointers);
    cout << "\n维修上次维修后飞行时间最长的飞机后的交通工具信息(Vehicles after repairing the aeroplane with max flight time since last repair):" << endl;
    DisplayVehicles(vehiclePointers);

    return 0;
}

关系图