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
相关产品推荐
相关产品推荐

