如何阻止C++中用int而非int&继承MyApplication的代码编译?
解决方案
要强制所有继承MyApplication的子类必须使用int&作为构造函数的第一个参数,同时避免现有代码继续使用错误的int参数,可以采用以下几种方法:
方法一:CRTP静态断言(编译时强制检查)
通过奇异递归模板模式(CRTP)在编译期检查子类的构造函数类型,不符合要求的代码会直接报错,帮你快速定位所有需要修改的旧代码,同时阻止新代码重蹈覆辙。
步骤1:重构MyApplication为CRTP基类
#include <type_traits> #include <QApplication> template<typename Derived> class MyApplication : public QApplication { protected: // 仅允许子类通过int&调用构造 MyApplication(int& argc, char** argv) : QApplication(argc, argv) {} public: // 静态断言:子类必须定义接受int&类型argc的构造函数 static_assert(std::is_constructible_v<Derived, int&, char**>, "子类必须定义接受int&类型argc的构造函数"); // 静态断言:禁止子类定义接受int类型argc的构造函数 static_assert(!std::is_constructible_v<Derived, int, char**>, "子类不能定义接受int类型argc的构造函数"); };
步骤2:修改子类继承方式
所有继承MyApplication的子类需要改为继承MyApplication<Derived>:
// 正确写法:编译通过 class CorrectApplication : public MyApplication<CorrectApplication> { public: CorrectApplication(int& argc, char** argv) : MyApplication(argc, argv) {} }; // 错误写法:编译时触发静态断言报错 class WrongApplication : public MyApplication<WrongApplication> { public: WrongApplication(int argc, char** argv) : MyApplication(argc, argv) {} };
方法二:工厂函数+protected构造函数(彻底避免错误调用)
将MyApplication的构造函数设为protected,仅通过静态工厂函数创建实例,从根源上强制所有调用必须传递int&。
步骤1:修改MyApplication
#include <memory> #include <QApplication> class MyApplication : public QApplication { protected: MyApplication(int& argc, char** argv) : QApplication(argc, argv) {} public: // 仅允许通过该工厂函数创建实例,强制接受int& static std::unique_ptr<MyApplication> create(int& argc, char** argv) { return std::make_unique<MyApplication>(argc, argv); } };
步骤2:修改子类实现
子类同样需要将构造函数设为protected,并提供对应的工厂函数:
class OtherApplication : public MyApplication { protected: OtherApplication(int& argc, char** argv) : MyApplication(argc, argv) {} public: static std::unique_ptr<OtherApplication> create(int& argc, char** argv) { return std::make_unique<OtherApplication>(argc, argv); } };
步骤3:修改实例化代码
所有创建MyApplication或其子类实例的代码,都需要改为调用create函数:
int main(int argc, char** argv) { auto app = MyApplication::create(argc, argv); // ... return app->exec(); }
方法三:快速定位旧代码(临时过渡)
如果你需要先找出所有需要修改的旧子类,可以用以下方式快速排查:
- 编译器警告:GCC/Clang启用
-Wconversion警告,帮助定位传递int参数的调用点; - 静态分析:用Clang-Tidy编写自定义规则,检查所有继承
MyApplication的类的构造函数参数类型; - 文本搜索:通过grep等工具查找所有继承
MyApplication的类,再逐一检查构造函数参数。
内容的提问来源于stack exchange,提问作者jpo38
相关产品推荐
相关产品推荐

