新增基类结构体后C++函数重载失效问题求助
你遇到的问题是C++中函数隐藏导致的:当子类LexerResult定义了自己的add(Token)成员函数后,基类Result中所有同名的add方法会被自动隐藏,编译器不会将它们视为重载关系。
具体原因
C++的名字查找规则是:当查找成员函数时,编译器会优先在当前类(LexerResult)的作用域中寻找同名函数。一旦找到add(Token),就会停止向上查找基类的其他add重载(add(Warning)、add(Error))。
所以你调用result.add(Error { loc, "Unknown token" });时,编译器只会尝试匹配LexerResult::add(Token),它无法将Error对象转换为Token,因此抛出"No viable conversion from 'Warning' to 'Token'"的错误(报错信息中的Warning大概率是笔误,实际是无法转换Error到Token)。
解决方案
有三种常见的解决方式:
显式指定基类作用域调用
就是你看到的自动补全提示写法,强制让编译器去基类中查找add方法:result.Result::add(Error { loc, "Unknown token" });在子类中引入基类的
add方法(推荐)
在LexerResult结构体中添加using Result::add;,将基类的所有add重载引入子类作用域,和子类的add(Token)构成正确的重载关系:struct LexerResult : public Result { std::vector<Token> tokens; using Result::add; // 引入基类的所有add重载 void add(Token token) { tokens.push_back(token); } };这样原来的
result.add(Error{...})调用就能正常编译,无需修改调用代码。手动在子类中重载基类方法
逐个实现基类的add方法,调用基类版本:struct LexerResult : public Result { std::vector<Token> tokens; void add(Token token) { tokens.push_back(token); } void add(Warning warning) { Result::add(warning); } void add(Error error) { Result::add(error); } };这种方法繁琐,仅适用于无法使用
using的场景。
内容的提问来源于stack exchange,提问作者CaseyB

