如何将文本文件中的游戏分类至对应类并调用多态getMonthlyCost函数?
我来一步步帮你解决这个问题。首先你的现有代码存在不少语法和设计问题,得先修正这些,才能顺利实现从文本文件加载游戏并调用对应方法的功能。接下来我们会搞定文件解析和对应类对象的实例化,最后再给你一些改进建议。
第一步:修复类结构的核心问题
你的原代码有很多影响功能实现的问题,先逐一修正:
- 重复定义成员变量:子类(比如MMO、Strategy)不需要重新定义
Name和Description,基类Game/Console已经有这些成员,应该把基类的成员设为protected,让子类可以直接访问,避免冗余。 - 构造函数访问权限与初始化错误:基类
Game和Console的构造函数默认是私有,子类无法调用;而且子类构造函数的初始化列表写法错误,比如PC():Game(Name,Description)里的Name是未初始化的局部变量,应该通过构造函数参数传入值。 - 多态接口缺失:要实现多态调用
getMonthlyCost,基类必须定义一个虚函数作为接口,最好是纯虚函数,强制子类实现自己的版本。 - 函数语法错误:
getMonthlyCost函数没有返回值,而且表达式没有return语句;构造函数末尾缺少分号。
修正后的基类和子类示例:
#include <iostream> #include <fstream> #include <vector> #include <memory> #include <string> using namespace std; // 抽象基类:Game,所有游戏的父类 class Game { protected: string Name; string Category; // 用Category代替Description更贴合业务场景 public: Game(string name, string category) : Name(move(name)), Category(move(category)) {} // 纯虚函数,强制子类实现月费计算逻辑 virtual double getMonthlyCost() const = 0; virtual ~Game() = default; // 虚析构函数,避免内存泄漏 string getName() const { return Name; } string getCategory() const { return Category; } }; // PC游戏基类,继承自Game class PCGame : public Game { protected: double basePrice; public: PCGame(string name, string category, double basePrice) : Game(move(name), move(category)), basePrice(basePrice) {} }; // MMO子类 class MMO : public PCGame { private: const double monthlyFee = 14.99; // 固定月费 public: MMO(string name, double basePrice) : PCGame(move(name), "MMO", basePrice) {} double getMonthlyCost() const override { return monthlyFee; // MMO只收取固定月费 } }; // Strategy子类 class Strategy : public PCGame { private: const double monthlyServiceRate = 0.05; // 每月收取基础价的5%作为服务费 public: Strategy(string name, double basePrice) : PCGame(move(name), "Strategy", basePrice) {} double getMonthlyCost() const override { return basePrice * monthlyServiceRate; // 计算月服务费 } }; // Console游戏基类,继承自Game class ConsoleGame : public Game { protected: double basePrice; public: ConsoleGame(string name, string category, double basePrice) : Game(move(name), move(category)), basePrice(basePrice) {} }; // Arcade子类 class Arcade : public ConsoleGame { public: Arcade(string name, double basePrice) : ConsoleGame(move(name), "Arcade", basePrice) {} double getMonthlyCost() const override { return basePrice + (basePrice * 0.10); // 基础价加10%服务费 } }; // AR子类 class AR : public ConsoleGame { private: double equipmentCost; public: AR(string name, double basePrice, double equipmentCost) : ConsoleGame(move(name), "AR", basePrice), equipmentCost(equipmentCost) {} double getMonthlyCost() const override { return equipmentCost + basePrice; // 设备费加基础月费 } };
第二步:从文本文件加载游戏并实例化对应类
接下来我们需要读取文本文件,每两个条目为一组(游戏名+分类),然后根据分类创建对应的子类对象,用基类智能指针存储,这样就能实现多态调用getMonthlyCost。
假设你的文本文件games.txt内容格式如下(每行一个条目,两两一组):
League Of Legends MMO World Of Warcraft MMO Civilization Strategy Hearthstone Strategy Street Fighter Arcade PacMan Arcade Beat Saber AR Superhot AR
读取并处理的代码:
int main() { vector<unique_ptr<Game>> gameList; ifstream file("games.txt"); if (!file.is_open()) { cerr << "无法打开游戏文件!" << endl; return 1; } string gameName, category; // 每读取两行:第一行是游戏名,第二行是分类 while (getline(file, gameName) && getline(file, category)) { // 根据分类创建对应对象(这里的基础价/设备费是示例值,你可以写到文件里或者从配置读取) if (category == "MMO") { gameList.emplace_back(make_unique<MMO>(gameName, 0.0)); } else if (category == "Strategy") { gameList.emplace_back(make_unique<Strategy>(gameName, 59.99)); } else if (category == "Arcade") { gameList.emplace_back(make_unique<Arcade>(gameName, 19.99)); } else if (category == "AR") { gameList.emplace_back(make_unique<AR>(gameName, 29.99, 99.99)); } else { cerr << "未知分类:" << category << ",跳过游戏:" << gameName << endl; } } // 遍历所有游戏,调用getMonthlyCost计算并输出月费 cout << "各游戏月费用计算结果:" << endl; for (const auto& game : gameList) { cout << "游戏:" << game->getName() << ",分类:" << game->getCategory() << ",月费用:$" << game->getMonthlyCost() << endl; } return 0; }
关键改进与批评建议
- 类设计冗余:原代码重复定义
Name和Description属于典型的冗余设计,基类成员设为protected即可让子类访问,减少维护成本和内存浪费。 - 多态实现错误:原代码没有在基类定义虚函数,导致无法实现多态调用;子类的
virtual用法也有误(基类声明虚函数后,子类用override标记即可)。 - 语法漏洞:原代码的构造函数缺少分号、
getMonthlyCost无返回值,这些都是编译级错误,必须优先修正。 - 扩展性优化建议:
- 可以把游戏的基础价格、设备费等信息也写入文本文件,避免代码硬编码,提升灵活性。
- 使用
unique_ptr代替原始指针,自动管理内存,避免内存泄漏。 - 可以封装工厂模式,把创建游戏对象的逻辑单独抽离,简化
main函数的复杂度。 - 把
getMonthlyCost设为const成员函数,因为它不会修改对象状态,符合代码规范。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

