C++私有继承下如何在运行时选择RTC硬件类型?
解决私有继承导致的运行时多态问题
由于RTC_DS3231采用私有继承RTC_I2C,无法直接将其对象指针转换为RTC_I2C*实现运行时多态。以下是几种可行的解决方法:
方法一:封装统一抽象接口类(推荐)
创建一个新的抽象基类,定义你需要的所有RTC操作接口(如设置时间、获取时间等),再分别为两个RTC类编写适配器,继承该抽象类并封装对应RTC的方法。
示例代码:
// 定义统一的RTC操作接口 class RTC_Interface { public: virtual ~RTC_Interface() = default; virtual void adjust(const DateTime& dt) = 0; // 设置时间 virtual DateTime now() = 0; // 获取当前时间 // 根据需求添加其他API }; // 适配RTC_DS3231的包装类 class RTC_DS3231_Adapter : public RTC_Interface { private: RTC_DS3231 rtc; public: void adjust(const DateTime& dt) override { rtc.adjust(dt); } DateTime now() override { return rtc.now(); } // 其他接口按同样方式封装 }; // 适配RTC_M41T83的包装类 class RTC_M41T83_Adapter : public RTC_Interface { private: RTC_M41T83 rtc; public: void adjust(const DateTime& dt) override { rtc.adjust(dt); } DateTime now() override { return rtc.now(); } // 其他接口按同样方式封装 }; // 运行时选择RTC类型 RTC_Interface* rtc; if(use_RTC_M41T83) { rtc = new RTC_M41T83_Adapter; } else { rtc = new RTC_DS3231_Adapter; } // 通过统一接口调用操作 rtc->adjust(DateTime(2024, 5, 20, 12, 0, 0)); DateTime current = rtc->now();
这种方式彻底隔离了原有类的继承限制,通过适配器实现了清晰的运行时多态,代码易维护、扩展性强。
方法二:用函数指针/std::function封装(轻量方案)
如果需要的RTC接口不多,可以直接用函数对象封装所需操作,避免定义额外类。
示例代码:
#include <functional> // 定义操作对应的函数类型 using AdjustFunc = std::function<void(const DateTime&)>; using NowFunc = std::function<DateTime()>; // 存储绑定后的函数对象 AdjustFunc rtc_adjust; NowFunc rtc_now; // 初始化时绑定对应RTC的方法 if(use_RTC_M41T83) { static RTC_M41T83 rtc; rtc_adjust = [&rtc](const DateTime& dt) { rtc.adjust(dt); }; rtc_now = [&rtc]() { return rtc.now(); }; } else { static RTC_DS3231 rtc; rtc_adjust = [&rtc](const DateTime& dt) { rtc.adjust(dt); }; rtc_now = [&rtc]() { return rtc.now(); }; } // 调用操作 rtc_adjust(DateTime(2024, 5, 20, 12, 0, 0)); DateTime current = rtc_now();
该方案更轻量,适合接口较少的场景,但接口过多时代码会显得零散。
方法三:CRTP静态多态(编译时选择)
如果可以接受编译时确定RTC类型(比如通过宏定义切换),可以用CRTP实现静态多态,避免运行时开销。
示例代码:
template<typename RTCImpl> class RTC_Wrapper { private: RTCImpl rtc; public: void adjust(const DateTime& dt) { rtc.adjust(dt); } DateTime now() { return rtc.now(); } }; // 通过宏选择RTC类型 #ifdef USE_M41T83 RTC_Wrapper<RTC_M41T83> rtc; #else RTC_Wrapper<RTC_DS3231> rtc; #endif // 直接调用操作 rtc.adjust(DateTime(2024, 5, 20, 12, 0, 0)); DateTime current = rtc.now();
此方案无运行时多态开销,但需在编译阶段确定使用的RTC类型,适合不需要动态切换的场景。
内容的提问来源于stack exchange,提问作者fakbill
相关产品推荐
相关产品推荐

