模板特化类重写基类虚方法时的编译错误问题解决
问题重现
定义模板基类BasicContext,派生类MyclassContext继承自BasicContext<Myclass*>,尝试重写基类的virtual isValid虚方法时,触发MSVC的C3668编译错误,提示带override修饰符的方法未覆盖任何基类方法。
头文件代码
template <class T> struct BasicContext { BasicContext() {} bool operator() (const T i) const { return isValid(i); } virtual bool isValid(const T) const { return true; } virtual BasicContext* Clone() const { return(new BasicContext<T>()); } }; class Myclass { public: Myclass() { } }; class MyclassContext : public BasicContext<Myclass*> { public: MyclassContext(); bool isValid(const Myclass* bdry) const override; BasicContext* Clone() const override; };
cpp文件代码
bool MyclassContext::isValid(const Myclass* m) const { return true; } BasicContext<Myclass*>* MyclassContext::Clone() const { return new MyclassContext(); }
编译错误
Severity Code Description Project File Line Suppression State
Error C3668 'MyclassContext::isValid': method with override specifier 'override' did not override any base class methods DbgError F:\C++\DbgError\DbgError\Dummy.h 36
错误原因
核心问题是参数类型不匹配:
当基类模板实例化为BasicContext<Myclass*>时,isValid的参数const T实际是Myclass* const(即「指向Myclass对象的常量指针」——指针本身不可修改,但指向的对象可以修改);而派生类中声明的const Myclass*是「指向常量Myclass对象的指针」——指针本身可以修改,但指向的对象不可修改。这两个类型完全不同,因此编译器判定派生类的isValid没有覆盖基类方法。
另外,Clone方法的声明也存在不一致:基类中Clone返回BasicContext<T>*(即BasicContext<Myclass*>*),但派生类头文件中声明为BasicContext*(未指定模板参数的基类指针),虽然cpp实现是正确的,但这种写法容易引发歧义。
解决方案
方案1:匹配基类的参数类型
将派生类isValid的参数改为Myclass* const,与基类实例化后的参数类型完全一致:
修改后的头文件片段
class MyclassContext : public BasicContext<Myclass*> { public: MyclassContext(); bool isValid(Myclass* const bdry) const override; BasicContext<Myclass*>* Clone() const override; // 修正Clone的返回类型声明 };
修改后的cpp片段
bool MyclassContext::isValid(Myclass* const m) const { return true; }
方案2:使用模板参数T保持一致性(更推荐)
直接在派生类中使用基类的模板参数T来声明参数类型,避免手动书写指针类型时出错:
修改后的头文件片段
class MyclassContext : public BasicContext<Myclass*> { public: MyclassContext(); bool isValid(const T bdry) const override; // T即Myclass*,const T等价于Myclass* const BasicContext<T>* Clone() const override; // 用T代替具体类型,更通用 };
修改后的cpp片段
bool MyclassContext::isValid(const T m) const { return true; }
这样无论基类模板的T是什么类型,派生类的方法都会自动匹配基类的参数类型,避免类型不匹配的问题。
内容的提问来源于stack exchange,提问作者user6771624

