我有以下代码:
struct CommonVariables
{/*some common variables that need to be proceed*/};
struct CommonHandler
{
static void foo(const CommonVariables& vars) {/*processed vars*/}
void bar(const CommonVariables& vars) {/*processed vars*/}
};
struct AnotherVariables
{/*another variables*/};
struct AnotherHandler
{
static void foo(const AnotherVariables& vars) {/*processed vars*/}
void bar(const AnotherVariables& vars) {/*processed vars*/}
};
struct Derived : CommonHandler, AnotherHandler
{};
当我尝试调用Derived :: foo(/ 任何变量类型 /)或Derived d时; d.bar(/ 任何变量类型 /),编译器给我一个错误:“引用'foo(或bar)'是不明确的”。
然而,下面我的情况几乎相同:
struct DifferentHandler
{
static void foo(const CommonVariables& vars) {}
static void foo(const AnotherVariables& vars) {}
void bar(const AnotherVariables& vars) {}
void bar(const CommonVariables& vars) {}
};
调用DifferentHandler :: foo(/ 任何变量类型 /)或'bar'都可以正常工作。
有很多解决方案可以解决第一个代码块(template traits等)。我特别想要的是通过继承来重载方法。我不明白为什么来自Derived的调用是模糊的(因为输入参数有不同的类型,从编译器的角度看这些函数是不同的。就像在DifferentHandler中一样)
注意:我在VS2015中尝试过MinGW5.8(在Qt Creator中)和MSVC2015。两个编译器都生成了相同的错误。
答案 0 :(得分:2)
你走了:
struct Derived : CommonHandler, AnotherHandler
{
using CommonHandler::foo;
using CommonHandler::bar;
using AnotherHandler::foo;
using AnotherHandler::bar;
};
修复您的问题。
原始代码不起作用的原因可以在C ++标准中找到。以下是有趣的引语:
在10/2:
基类成员据说由派生类继承。 可以以相同的方式在表达式中引用继承的成员 作为派生类的其他成员,除非它们的名称被隐藏 或含糊不清(10.2)。
继续阅读10.2:
成员名称查找确定名称(id-expression)的含义 一个范围(3.3.7)。名称查找可能导致歧义 该案件的格式错误......
...由两个组件集组成:声明集,a 成员名为 f ...
如果明确找到重载函数的名称,则在访问控制之前也会发生重载分辨率(13.3)
基本上,它首先按名称命名并稍后应用解决方案。通过using
声明将它们引入派生类会将它们全部放在派生类的范围内,其中正常的解析规则会被启动。
答案 1 :(得分:0)
在C ++中,如果派生类的成员函数与基类的成员函数具有相同的名称,则派生类的版本隐藏基本版本 - 甚至如果函数签名不同,否则你会希望它们超载。 (如果基类成员函数是虚拟的,那么派生类的签名必须完全匹配*,否则它(通常是无意中)隐藏基类的版本 - 这就是C ++ 11的原因添加了override
psuedo-keyword)。
例如:
struct base {
void foo(std::string s) {}
};
struct derived : base {
void foo(int i) {}
};
int main() {
derived d;
d.foo("hello"); // Error -- cannot convert const char* to int
}
解决方案是使用using
指令将基类的成员函数带入派生类范围,即
struct derived : base {
using base::foo;
void foo(int i) {}
};
(另一种方法是使用晦涩的
derived d;
d.base::foo("hello"); // works
语法指定您要调用基类版本,但这在现实世界中很少见。)