我需要解释为什么以下代码无法编译。我有一个解决方法,下面将详细说明,但我不了解原始版本的失败。
加快代码读取速度:概念是定义一个接口(interface)(ISomething
),然后创建一个抽象实现(ASomething
),该抽象实现使用第一个(尚未定义)一个(2)
实现第二个函数(1)
。从抽象方法(例如SomethingImpl
)派生的完整实现必须定义第一个方法,并可以选择覆盖第二个方法。
#include <iostream>
class ISomething
{
public:
virtual ~ISomething()
{ }
virtual int f(int x) = 0; // (1)
virtual int f(int x, int y) = 0; // (2)
};
class ASomething
: public virtual ISomething
{
public:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
};
class SomethingImpl
: public ASomething
{
public:
virtual int f(int x) // (1)
{
return x+1;
}
};
int main()
{
SomethingImpl a;
std::cout << a.f(10) << std::endl; // (1)
std::cout << a.f(10,20) << std::endl; // (2)
return 0;
}
编译此代码会在Visual Studio 2013(Windows)和g++ 4.4.5(Linux)上产生错误。错误非常相似,我将仅详细介绍g++输出:
$ g++ SibFun.cpp -o SibFun
SibFun.cpp: In member function ‘virtual int ASomething::f(int, int)’:
SibFun.cpp:18: error: no matching function for call to ‘ASomething::f(int&)’
SibFun.cpp:16: note: candidates are: virtual int ASomething::f(int, int)
SibFun.cpp:18: error: no matching function for call to ‘ASomething::f(int&)’
SibFun.cpp:16: note: candidates are: virtual int ASomething::f(int, int)
SibFun.cpp: In function ‘int main()’:
SibFun.cpp:36: error: no matching function for call to ‘SomethingImpl::f(int, int)’
SibFun.cpp:26: note: candidates are: virtual int SomethingImpl::f(int)
make: *** [SibFun] Error 1
我尝试在
(3)
上使用不同的表示法,例如return this->f(x) + this->f(y)
,但是在错误消息中我没有经历任何重大变化。但是,当我将
(3)
更改为return ISomething::f(x) + ISomething::f(y);
时,我只有:$ g++ SibFun.cpp -o SibFun
SibFun.cpp: In function ‘int main()’:
SibFun.cpp:36: error: no matching function for call to ‘SomethingImpl::f(int, int)’
SibFun.cpp:26: note: candidates are: virtual int SomethingImpl::f(int)
make: *** [SibFun] Error 1
但!当将
(2)
从f
更改为g
时,所有编译和运行均会按预期进行。这种行为背后的原因是什么?为什么我不能使用
f
名称作为(2)
? 最佳答案
两种编译失败的发生原因均相同。当您覆盖一个虚拟成员函数时,您将隐藏另一个。在ASomething
中:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
在
f
上进行名称查找会找到ASomething::f
并停止,它不会继续寻找其他重载。由于ASomething::f
接受两个参数,并且您尝试使用一个参数进行调用,因此错误。为了允许对基类进行重载,您必须使用using-declaration引入基类成员函数:using ISomething::f; // NOW, ISomething::f(int ) is found by lookup
virtual int f(int x, int y)
{
return f(x) + f(y);
}
同样,
SomethingImpl
需要using ASomething::f;
语句,以便a.f(10)
可以编译。