【发布时间】:2014-05-28 08:28:38
【问题描述】:
有一句引自 3.4.1/7:
在查找引入的类或函数的先前声明时 通过朋友声明,范围在最里面的封闭之外 不考虑命名空间范围;
你能举个例子来说明这个规则吗?
【问题讨论】:
-
cppreference 的Name Lookup 部分对此以及许多其他有趣的查找条件有相当可靠的描述。值得一读。
标签: c++ namespaces friend
有一句引自 3.4.1/7:
在查找引入的类或函数的先前声明时 通过朋友声明,范围在最里面的封闭之外 不考虑命名空间范围;
你能举个例子来说明这个规则吗?
【问题讨论】:
标签: c++ namespaces friend
当然。此代码有效(两个类都在同一个命名空间中):
namespace Foo {
class Bar
{
friend class FooBar;
public:
Bar() : i(0){}
private:
int i;
};
class FooBar
{
FooBar( Bar & other )
{
other.i = 1;
}
};
}//namespace Foo
并且此代码失败(朋友类在Foo 的封闭命名空间之外,因此查找失败并且您会看到int Foo::i is private within this context 错误):
namespace Foo {
class Bar
{
friend class FooBar;
public:
Bar() : i(0){}
private:
int i;
};
}//namespace Foo
class FooBar
{
FooBar( Foo::Bar & other )
{
other.i = 1;//Oops :'(
}
};
【讨论】:
此规则规定编译器在哪里寻找标记为friend 的函数或类。它规定,编译器将只检查与允许friend 访问的类在同一命名空间中的函数或类。它不会检查其他或外部命名空间中的函数或类。
这段代码会产生错误:
#include <iostream>
namespace a {
class Q { int x; friend void foo(Q q); };
}
// function foo is in outer namespace (not in a)
void foo(a::Q q) { std::cout << q.x << std::endl; }
// ^^^ ERROR q.x is private
int main() {
a::Q q;
foo(q);
}
原因是函数foo 不在命名空间a 中,而是在外部命名空间(在本例中为全局命名空间)。因此foo 与Q 中的朋友声明不匹配。
此代码将起作用:
#include <iostream>
namespace a {
class Q { int x; friend void foo(Q q); };
}
// function foo is in same namespace as Q
namespace a {
void foo(Q q) { std::cout << q.x << std::endl; }
// ^^^ OK access allowed by friend
}
int main() {
a::Q q;
a::foo(q);
}
这是可行的,因为函数 foo 现在与 Q 在同一个命名空间中。因此foo 匹配Q 中的朋友声明。
【讨论】: