C++:方法重载的奇怪行为
C++: Weird behavior on method overloading
我需要解释以下代码无法编译的原因。我有一个解决方法,我将在下面详细说明,但我不明白原始版本的失败。
为了加快代码阅读:概念是定义一个接口(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
时,所有编译和运行都按预期进行。
这种行为背后的原因是什么?为什么我不能为 (2)
使用 f
名称?
函数重载仅适用于同一范围内可见的函数:
class ASomething
: public virtual ISomething
{
public:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
using ISomething::f;
//~~~~~~~~~~~~~~~~~^
};
class SomethingImpl
: public ASomething
{
public:
virtual int f(int x) // (1)
{
return x+1;
}
using ASomething::f;
//~~~~~~~~~~~~~~~~~^
};
两次编译失败的原因相同。当您覆盖一个虚拟成员函数时,您隐藏了另一个。在 ASomething
:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
f
上的名称查找找到 ASomething::f
并停止,它不会继续寻找其他重载。因为 ASomething::f
有两个参数,而你试图用一个参数调用它,错误。为了允许对基础 class 进行重载,您必须使用 using-declaration:
引入基础 class 成员函数
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)
可以编译。
问题不是 'overloading' 问题,而是隐藏了一个基础 class 函数(参见其他答案)
稍作修改的示例:
#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)
{
// `this->f(x)` fails:
ISomething& i = *this;
return i.f(x) + i.f(y); // (3)
}
};
class SomethingImpl: public ASomething
{
public:
virtual int f(int x) // (1)
{
return x+1;
}
};
int main()
{
SomethingImpl a;
// `a.f(10, 20)` fails:
ISomething& i = a;
std::cout << i.f(10) << std::endl; // (1)
std::cout << i.f(10, 20) << std::endl; // (2)
return 0;
}
因此,从界面调用f
,解决了冲突。虽然,您应该考虑 using base::f
,如其他答案中所建议的那样。
我需要解释以下代码无法编译的原因。我有一个解决方法,我将在下面详细说明,但我不明白原始版本的失败。
为了加快代码阅读:概念是定义一个接口(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
时,所有编译和运行都按预期进行。
这种行为背后的原因是什么?为什么我不能为 (2)
使用 f
名称?
函数重载仅适用于同一范围内可见的函数:
class ASomething
: public virtual ISomething
{
public:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
using ISomething::f;
//~~~~~~~~~~~~~~~~~^
};
class SomethingImpl
: public ASomething
{
public:
virtual int f(int x) // (1)
{
return x+1;
}
using ASomething::f;
//~~~~~~~~~~~~~~~~~^
};
两次编译失败的原因相同。当您覆盖一个虚拟成员函数时,您隐藏了另一个。在 ASomething
:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
f
上的名称查找找到 ASomething::f
并停止,它不会继续寻找其他重载。因为 ASomething::f
有两个参数,而你试图用一个参数调用它,错误。为了允许对基础 class 进行重载,您必须使用 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)
可以编译。
问题不是 'overloading' 问题,而是隐藏了一个基础 class 函数(参见其他答案)
稍作修改的示例:
#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)
{
// `this->f(x)` fails:
ISomething& i = *this;
return i.f(x) + i.f(y); // (3)
}
};
class SomethingImpl: public ASomething
{
public:
virtual int f(int x) // (1)
{
return x+1;
}
};
int main()
{
SomethingImpl a;
// `a.f(10, 20)` fails:
ISomething& i = a;
std::cout << i.f(10) << std::endl; // (1)
std::cout << i.f(10, 20) << std::endl; // (2)
return 0;
}
因此,从界面调用f
,解决了冲突。虽然,您应该考虑 using base::f
,如其他答案中所建议的那样。