C++朋友函数被类函数隐藏
C++ friend function hidden by class function?
最小示例:
class A
{
friend void swap(A& first, A& second) {}
void swap(A& other) {}
void call_swap(A& other)
{
swap(*this, other);
}
};
int main() { return 0; }
g++4.7表示:
friend.cpp: In member function ‘void A::call_swap(A&)’:
friend.cpp:7:20: error: no matching function for call to ‘A::swap(A&, A&)’
friend.cpp:7:20: note: candidate is:
friend.cpp:4:7: note: void A::swap(A&)
friend.cpp:4:7: note: candidate expects 1 argument, 2 provided
评论第4行:
// void swap(A& other) {}
而且效果很好。如果我想保留交换函数的两个变体,为什么以及如何解决这个问题?
我相信这是因为编译器试图在类中找到函数。这应该是一个最小的改变,使其工作(它在Visual Studio 2012中工作):
class A; // this and the next line are not needed in VS2012, but
void swap(A& first, A& second); // will make the code compile in g++ and clang++
class A
{
friend void swap(A& first, A& second) {}
void swap(A& other) {}
void call_swap(A& other)
{
::swap(*this, other); // note the scope operator
}
};
int main() { return 0; }
作为一种变通方法,您可以声明swap
的static
版本。然后,您可以声明friend
版本来调用static
版本。
class A
{
public:
friend void swap(A& first, A& second) { A::swap(first, second); }
private:
static void swap(A& first, A& second) {}
void swap(A& other) {}
void call_swap(A& other)
{
swap(*this, other);
}
};
int main () {
A a, b;
swap(a, b);
}
为什么选择
在类内部,类范围内的名称隐藏了周围命名空间中的名称;因此,friend(其名称在命名空间中起作用,但在命名空间中不能直接访问)被成员(在类中起作用)隐藏,在这里不能作为潜在的重载使用。(更新:或者可能比这更复杂,正如评论中提到的。范围和名称查找规则有点难以遵循,尤其是当涉及朋友时)。
如果我想保留交换函数的两个变体,如何解决这个问题?
没有完美的解决方案。如果两个函数都做相同的事情,那么只使用其他成员函数中的成员。如果您在类定义外部声明友元,那么它可以作为::swap
访问;但是,如果将类放在不同的命名空间中,这会有点脆弱。(Update:或者按照这个答案的建议使用静态成员函数;我没有想到)。
坚持标准的交换习惯用法,就不会有问题:
void call_swap(A& other) {
using std::swap;
swap(*this, other);
}
或者使用Boost.Swap包装:
void call_swap(A& other) {
boost::swap(*this, other);
}
这相当于@Juan的解决方案,只是你不是自己编写助手。
您还可以使用助手函数,如本例中的
template<class T>
void swap_elems(T& lhs, T& rhs)
{
using namespace std;
swap(lhs, rhs);
}
class A
{
friend void swap(A& first, A& second) { first.swap(second); }
public:
void swap(A& other) {}
void call_swap(A& other)
{
swap_elems(*this, other);
}
};
您在这里观察到的是,在没有friend
函数的先前声明的情况下,类中的friend
ship会将名称注入封闭命名空间,但不会注入类范围。在类范围内发生的唯一事情是,名为的函数被授予访问私有属性的权限。
这只在类作用域中留下一个交换函数(具有一个参数的成员),因此这是唯一的候选重载。一旦你找到了一个候选者,即使重载解析失败,你也永远不会尝试另一个封闭范围(阴影)。
如果你真的需要这两个版本(并且退一步确保你需要),那么把实现放到一个函数中,比如swap_impl
,你可以从朋友和成员那里调用它。
- 如何通过派生类函数更改基类中的向量
- 库函数需要一个 std::function<void(void)>,如何传入类函数?
- 在类函数中初始化外部作用域变量
- c++ 在非类函数中使用类变量
- SDL_PollEvent() 无法捕获类函数内部SDL_QUIT?
- 从类成员函数到类 C 函数指针的转换
- 如何在模板类函数中分配结构值?
- 如何使用类型别名从模板化类中隐藏模板列表
- 有没有办法将重载的类函数绑定到函数对象?
- static_assert:派生"must"中的某个函数隐藏了Base的类函数
- 为什么基类函数没有被同名的派生类函数隐藏
- 有没有一种聪明的方法可以禁止通过派生类之一隐藏基类的运算符函数
- 禁用或隐藏C++中的某些父类函数
- C++朋友函数被类函数隐藏
- 为什么继承的函数隐藏在这个代码的基类中
- 防止重写和/或隐藏基类函数(C++11)
- 如何处理基类函数已经重载不同访问权限时的名称隐藏问题
- 基类模板成员函数隐藏在派生类中,尽管参数列表不同
- 为什么派生类重载函数隐藏基类函数
- 在模板类中隐藏成员函数