部分重写虚函数的实现疑问:基于BakedGood抽象类的ToString函数
用模板方法模式实现“部分重写”的虚函数需求
这场景太常见了!要实现「固定逻辑(价格格式)父类管,可变内容(物品描述)子类做」的效果,用模板方法模式刚好能完美解决,既符合虚函数的设计思路,又能避免重复代码。
核心思路
把ToString的整体框架放在父类BakedGood里,把可变的物品描述部分抽成一个纯虚函数,让子类各自实现。父类的ToString负责把子类的描述和统一格式化的价格拼接起来,这样就实现了“部分重写”——子类只需要关心自己专属的内容,不用管价格的格式化逻辑。
代码实现示例
父类 BakedGood 定义
#include <string> #include <sstream> #include <iomanip> class BakedGood { protected: double price; // 价格由父类维护,子类通过构造函数初始化 public: // 构造函数初始化价格 BakedGood(double p) : price(p) {} // 抽象类必须有虚析构,避免内存泄漏 virtual ~BakedGood() = default; // 纯虚函数:子类必须实现自己的物品描述 virtual std::string GetItemDetails() const = 0; // 虚函数:父类实现完整的ToString逻辑,子类可按需重写(这里不需要) virtual std::string ToString() const { std::ostringstream oss; // 拼接子类的描述 + 统一格式的价格 oss << GetItemDetails() << " ($" << std::fixed << std::setprecision(2) << price << ")"; return oss.str(); } };
子类 CupCake 实现
class CupCake : public BakedGood { private: std::string flavor; std::string frosting; std::string sprinkles; public: CupCake(double price, std::string flavor, std::string frosting, std::string sprinkles) : BakedGood(price), flavor(std::move(flavor)), frosting(std::move(frosting)), sprinkles(std::move(sprinkles)) {} // 只需要实现自己的物品描述部分 std::string GetItemDetails() const override { return flavor + " cupcake with " + frosting + " frosting and " + sprinkles + " sprinkles"; } // 直接复用父类的ToString,不用重写 };
子类 Bread 实现
class Bread : public BakedGood { private: std::string breadType; public: Bread(double price, std::string breadType) : BakedGood(price), breadType(std::move(breadType)) {} std::string GetItemDetails() const override { return breadType + " bread"; } // 同样复用父类的ToString };
为什么这样做?
- 代码复用:价格格式化的逻辑(比如保留两位小数、$符号)只在父类写一次,所有子类共享,避免重复代码。
- 职责分离:子类只需要专注于自己的物品描述,不用关心整体字符串的拼接格式。
- 扩展性强:以后新增
Cookie、Muffin等子类,只需要实现GetItemDetails就行,ToString的逻辑完全不用改。 - 符合虚函数设计:通过纯虚函数强制子类实现必要的内容,父类的虚函数提供默认的完整逻辑,完美契合你要的“部分重写”需求。
测试示例
#include <iostream> int main() { BakedGood* cupcake = new CupCake(1.95, "Chocolate", "vanilla", "blue"); BakedGood* bread = new Bread(4.50, "Wheat"); std::cout << cupcake->ToString() << std::endl; std::cout << bread->ToString() << std::endl; delete cupcake; delete bread; return 0; }
输出结果:
Chocolate cupcake with vanilla frosting and blue sprinkles ($1.95) Wheat bread ($4.50)
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

