能否在不大规模重构的前提下将虚非静态方法转为静态方法?
问题描述
我希望把RecordCLDT::GetShortName(void)改成静态方法返回"CLDT",而且不想对项目做大规模重构。能不能用宏或者模板技巧实现?
要求:
- 必须保证
RecordCommon::DoSomeWork(void)能正确调用对应的GetShortName()函数(直接换成静态方法做不到这点) - 重写
RecordCommon的所有子类太费时间,而且虚函数版GetShortName()已经在代码里大量使用了
现有代码
class RecordCommon { public: virtual const char* GetShortName(void) const = 0; ... virtual void DoSomeWork(void); }; class RecordCLDT : public RecordCommon { virtual const char* GetShortName(void) const { return "CLDT"; } }; void RecordCommon::DoSomeWork(void) { ... log(GetShortName()); ... }
解决方案
方法一:用宏同时生成虚函数和静态方法
定义一个宏,在每个子类里展开后,同时创建静态GetShortName方法和重写的虚函数。这样既保留了原来的虚函数接口,又能通过类名直接调用静态方法,完全不影响现有代码里的虚函数调用。
示例代码:
// 定义宏,参数是类名和要返回的字符串 #define DEFINE_RECORD_SHORT_NAME(CLASS_NAME, NAME_STR) \ public: \ static const char* GetShortName(void) { return NAME_STR; } \ virtual const char* GetShortName(void) const override { return CLASS_NAME::GetShortName(); } // 修改子类,用宏替换原来的虚函数实现 class RecordCLDT : public RecordCommon { DEFINE_RECORD_SHORT_NAME(RecordCLDT, "CLDT") };
这样做的好处:
- 所有原来调用虚
GetShortName()的代码不用改,DoSomeWork里的调用依然能正常触发子类的实现 - 可以直接通过
RecordCLDT::GetShortName()调用静态方法 - 子类只需要替换原有的虚函数代码为这个宏,改动量极小
方法二:用模板基类统一实现
创建一个模板中间基类,把要返回的名称作为模板参数,自动生成静态方法和虚函数的实现。子类只需要继承这个模板类就行,不用手动写虚函数。
示例代码:
// 模板基类,继承自RecordCommon template<const char* Name> class RecordShortNameMixin : public RecordCommon { public: static const char* GetShortName(void) { return Name; } virtual const char* GetShortName(void) const override { return Name; } }; // 定义全局字符串常量(避免静态初始化顺序问题) constexpr const char cldtName[] = "CLDT"; // 修改子类的继承关系,替换成模板基类 class RecordCLDT : public RecordShortNameMixin<cldtName> { // 子类原来的其他代码完全不变 };
注意事项:
- 用C++11及以上版本的话,
constexpr能保证字符串在编译期就可用,没有运行时开销 - 子类只需要改继承的基类,其他代码不用动,重构成本极低
- 原有的虚函数调用逻辑完全不受影响,
DoSomeWork依然能正确拿到对应子类的名称
内容的提问来源于stack exchange,提问作者Dmitrii Motorygin
相关产品推荐
相关产品推荐

