You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

部分重写虚函数的实现疑问:基于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
};

为什么这样做?

  1. 代码复用:价格格式化的逻辑(比如保留两位小数、$符号)只在父类写一次,所有子类共享,避免重复代码。
  2. 职责分离:子类只需要专注于自己的物品描述,不用关心整体字符串的拼接格式。
  3. 扩展性强:以后新增Cookie、Muffin等子类,只需要实现GetItemDetails就行,ToString的逻辑完全不用改。
  4. 符合虚函数设计:通过纯虚函数强制子类实现必要的内容,父类的虚函数提供默认的完整逻辑,完美契合你要的“部分重写”需求。

测试示例

#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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:25:01