信息学实验室作业(一)
更新: 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
基类,包含抽象方法MakeTrip
和GetSpeed
。 - 实现了
Aeroplane
、Coach
和Automobile
类,并且重写了基类的抽象方法。 - 在
main
函数中使用srand(0)
初始化了随机数生成器,同时调用CommitRandomTrips
函数对交通工具对象进行了随机行程测试。所以该任务已完成。
- 代码中实现了
2. 信息管理与输出
- 任务内容:实现输入交通工具实例信息到对应数组的功能,并组织信息输出。输出方式包括按速度顺序从每个数组依次输出、按当前速度以统一列表输出、按输入顺序输出。可使用选择排序模板算法对数组指针进行排序,也可自定义比较函数。
- 完成情况:
- 代码中创建了存储不同交通工具对象的
vector
,并将对象指针存储在相应的指针vector
中。 - 实现了
DisplayVehicles
函数用于输出交通工具信息。 - 使用选择排序模板
SelectionSort
对交通工具指针数组按速度进行了排序并输出。 - 还实现了插入排序模板
InsertionSort
对交通工具指针数组按速度进行排序并输出。所以该任务已完成。
- 代码中创建了存储不同交通工具对象的
3. 完成拓展任务并再次测试
- 任务内容:从五个任务变体中任选其一完成并再次测试程序。变体 1 要求实现插入排序模板;变体 2 需在随机移动后找到上次维修后飞行时间最长的飞机并维修;变体 3 要基于汽车类派生电动汽车和汽油汽车类并添加相关属性;变体 4 实现多重继承的“汽车拖车”类;变体 5 为不同交通工具实现不同的价格计算算法。
- 完成情况:
- 实现了变体 1,即插入排序模板
InsertionSort
。 - 实现了变体 2,即
FindAndRepairMaxFlightTimeAeroplane
函数,用于找到上次维修后飞行时间最长的飞机并维修。所以该任务已完成。
- 实现了变体 1,即插入排序模板
4. 绘制类图
- 任务内容:完成上述任务后,绘制最终的类图,展示类之间的继承关系、属性和方法等。
- 完成情况:
- 提供了使用 Mermaid 语法绘制的类图,清晰展示了
Vehicle
、Aeroplane
、Coach
、Automobile
类之间的继承关系,以及类的属性和方法,还展示了Aeroplane
类与其内部类Computer
的组合关系。所以该任务已完成。
- 提供了使用 Mermaid 语法绘制的类图,清晰展示了
全部代码展示
通过对各项任务的检查,代码已完成了文档中要求的所有内容。不仅实现了基本的类和测试,完成了信息管理与输出,还完成了拓展任务中的两个变体,并绘制了相应的类图。
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;
}