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

C++类继承构造器写法咨询及电话账单计算类设计需求

嘿,我来帮你解决这两个C++类继承相关的问题,都是日常开发里很实用的知识点~

一、C++子类构造器的编写指南

在C++的类继承体系里,子类构造器的核心任务是既要初始化自身的成员,也要正确初始化继承自基类的部分。这里给你梳理几个关键要点:

  • 必须处理基类的初始化
    如果基类有默认构造器(无参数的那种),子类构造器会自动调用它来初始化基类部分。但如果基类只有带参数的构造器,那你必须在子类构造器的初始化列表里显式调用它,不然编译器会报错。举个例子:

    class Base {
    private:
        int coreValue;
    public:
        // 基类只有带参构造器
        Base(int val) : coreValue(val) {}
    };
    
    class Derived : public Base {
    private:
        string extraInfo;
    public:
        // 显式调用基类构造器,再初始化自己的成员
        Derived(int val, string info) : Base(val), extraInfo(info) {}
    };
    
  • 注意初始化顺序的坑
    初始化列表里写的顺序不影响实际的初始化顺序!实际是先初始化基类,然后按照子类成员在类里声明的顺序来初始化,和列表顺序无关。所以尽量让初始化列表的顺序和成员声明顺序一致,避免出现逻辑错误。

  • C++11的委托构造(可选)
    如果子类有多个构造器,可以委托同一个类里的其他构造器来减少重复代码。比如:

    class Derived : public Base {
    public:
        // 基础构造器,调用基类
        Derived(int val) : Base(val) {}
        // 委托给上面的构造器,再处理额外成员
        Derived(int val, string info) : Derived(val) {
            extraInfo = info;
        }
    };
    
  • 继承权限不影响构造调用
    不管是public、protected还是private继承,子类构造器都必须调用基类构造器,区别只是基类成员在子类里的访问权限不同而已。


二、电话账单计算的类继承实现方案

针对你提到的三种合约类型,我们可以用抽象基类+多态的方式来设计,既符合开闭原则,又能清晰区分不同合约的计费规则。先看完整的实现代码,再给你拆解思路:

第一步:定义抽象基类

基类负责封装所有合约共有的属性(通话单价、短信单价),并定义计费的统一接口:

#include <iostream>
#include <algorithm> // 用到max函数
using namespace std;

class BasePlan {
private:
    int minutesPrice; // 美元/分钟
    int smsPrice;     // 美元/条
protected:
    // 给子类提供访问单价的方法,保证封装性
    int getMinutesPrice() const { return minutesPrice; }
    int getSmsPrice() const { return smsPrice; }
public:
    // 基类构造器,初始化单价
    BasePlan(int minPrice, int smsPrice) : minutesPrice(minPrice), smsPrice(smsPrice) {}

    // 纯虚函数:子类必须实现具体的计费逻辑
    virtual double calculateBill(int totalMinutes, int totalSms) const = 0;

    // 虚析构函数:避免基类指针指向子类对象时的内存泄漏
    virtual ~BasePlan() = default;
};

第二步:实现各个子类合约

每个子类对应一种合约,实现自己的计费规则:

1. Basic合约(无免费短信)

class BasicPlan : public BasePlan {
public:
    // 初始化基类的单价:通话10$/分钟,短信5$/条
    BasicPlan() : BasePlan(10, 5) {}

    double calculateBill(int totalMinutes, int totalSms) const override {
        // 直接计算总费用:通话时长×单价 + 短信数量×单价
        return totalMinutes * getMinutesPrice() + totalSms * getSmsPrice();
    }
};

2. SMSGod合约(前150条短信免费)

class SMSGodPlan : public BasePlan {
private:
    static const int FREE_SMS_LIMIT = 150; // 免费短信上限
public:
    // 初始化基类的单价:通话10$/分钟,短信1$/条
    SMSGodPlan() : BasePlan(10, 1) {}

    double calculateBill(int totalMinutes, int totalSms) const override {
        // 计算需要收费的短信数量:总短信数-免费额度,最少为0
        int chargedSms = max(totalSms - FREE_SMS_LIMIT, 0);
        return totalMinutes * getMinutesPrice() + chargedSms * getSmsPrice();
    }
};

3. Upgraded合约(前25条短信免费)

class UpgradedPlan : public BasePlan {
private:
    static const int FREE_SMS_LIMIT = 25; // 免费短信上限
public:
    // 初始化基类的单价:通话5$/分钟,短信3$/条
    UpgradedPlan() : BasePlan(5, 3) {}

    double calculateBill(int totalMinutes, int totalSms) const override {
        int chargedSms = max(totalSms - FREE_SMS_LIMIT, 0);
        return totalMinutes * getMinutesPrice() + chargedSms * getSmsPrice();
    }
};

第三步:测试代码

可以写一个通用的测试函数,利用多态来调用不同合约的计费方法:

// 通用测试函数,接收任意合约对象
void printTotalBill(const BasePlan& plan, int minutes, int sms) {
    cout << "Total bill: $" << plan.calculateBill(minutes, sms) << endl;
}

int main() {
    BasicPlan basic;
    printTotalBill(basic, 10, 20); // 预期:10*10 + 20*5 = 200

    SMSGodPlan smsGod;
    printTotalBill(smsGod, 10, 200); // 预期:10*10 + (200-150)*1 = 150

    UpgradedPlan upgraded;
    printTotalBill(upgraded, 10, 30); // 预期:10*5 + (30-25)*3 = 65

    return 0;
}

设计思路说明

  • 封装性:基类把单价设为私有,通过protected的getter让子类访问,避免直接修改属性,保证数据安全。
  • 多态性:纯虚函数calculateBill定义了统一的计费接口,子类各自实现自己的规则,后续如果新增合约,只需要添加新的子类即可,不用修改原有代码。
  • 可维护性:每个合约的规则都封装在对应的子类里,逻辑清晰,便于修改和调试。

内容的提问来源于stack exchange,提问作者Malkalma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:43:27