Friend函数和命名空间
Friend functions and namespaces
我正试图重载<lt;属于用户定义命名空间一部分的类的运算符。有趣的是,如果我删除了所有的命名空间内容,程序编译和运行都没有问题,但类驻留在命名空间中的事实不知何故使文件a.cpp的编译过程失败,并出现一个错误,表示我正在尝试访问类a中的私有数据(demo.cpp编译良好(。请看一下我的三文件程序和我得到的编译错误:
demo.cpp:
#include <iostream>
#include "A.h"
int main() {
usr::A a(4);
std::cout << a << std::endl;
return 0;
}
A.h:
#ifndef A_H_
#define A_H_
#include <iostream>
namespace usr {
class A {
private:
int m_x;
public:
A(int x);
friend std::ostream& operator<<(std::ostream& os, const usr::A& a);
};
}
#endif // A_H_
A.cpp:
#include "A.h"
usr::A::A(int x) : m_x(x) {}
std::ostream& operator<<(std::ostream& os, const usr::A& a) {
os << a.m_x;
return os;
}
错误:
$ g++ -c A.cpp
In file included from A.cpp:1:0:
A.h: In function ‘std::ostream& operator<<(std::ostream&, const usr::A&)’:
A.h:10:17: error: ‘int usr::A::m_x’ is private
int m_x;
^
A.cpp:7:13: error: within this context
os << a.m_x;
^
非限定友元声明总是引用最小封闭命名空间的成员。当一个类在命名空间usr
中声明时,该类内的任何非限定友元声明都引用usr
的成员。即,您的好友声明将usr::operator <<
声明为好友。
在这种情况下,全局::operator <<
仍然是非好友,这就是为什么当您尝试从::operator <<
访问usr::A
的私有成员时会出现错误。
如果你想让它发挥作用,你必须要么
-
使您的
operator <<
成为usr
或的成员 -
确保友元声明通过使用限定名
::operator <<
显式引用全局operator <<
(这还需要在尝试通过其限定名引用它之前引入::operator <<
(。
我建议采取第一种方法。如果类A
是命名空间usr
的成员,那么最好将处理A
的所有函数也声明为usr
的成员。这将帮助您避免在以后的过程中出现与自变量相关的查找(ADL(的许多问题。
但是,如果出于某种原因,您需要您的operator <<
继续作为全局命名空间的成员,那么以下是您必须跳过的障碍,以使其编译(合并为一个翻译单元(
// Pre-declare `usr::A` to enable pre-declaration of our `::operator <<`
namespace usr {
class A;
}
// Pre-declare our `::operator <<`
std::ostream& operator<<(std::ostream& os, const usr::A& a);
namespace usr {
class A {
private:
int m_x;
public:
A(int x);
friend std::ostream& ::operator<<(std::ostream& os, const usr::A& a);
// Friend declaration uses qualified name - it explicitly
// refers to `::operator <<` declared above
};
}
usr::A::A(int x) : m_x(x) {}
std::ostream& operator<<(std::ostream& os, const usr::A& a) {
os << a.m_x;
return os;
}
int main() {
usr::A a(4);
std::cout << a << std::endl;
}
在GCC下,您必须通过一些访问修饰符(const或指针上的引用(来分离返回类型和范围解析运算符(::
令牌(。
例如,这个不会在g++7.2.0:下编译
std::string f(int a);
namespace NS
{
class C
{
friend std::string ::f(int a);
// scope operator ^^ is absolutely needed
}
}
但这个将:
std::string f(int a);
namespace NS
{
class C
{
friend std::string const ::f(int a);
// see const keyword ^
}
}
这个将:
std::string f(int a);
namespace NS
{
class C
{
friend std::string& ::f(int a);
// see ref symbol ^
}
}
- 在命名空间中定义函数还是限定函数
- CUDA内核和数学函数的显式命名空间
- 在命名空间中使用全局命名空间中的函数
- 是否可以将函数导入命名空间,但不能导出它?
- 使用另一个命名空间中的函数C++
- Visual Studio 无法解决类和命名空间中重载的明确函数
- 命名空间更改函数定义
- C++命名空间中调用 void 函数的错误
- C++ 17 个友元函数声明和内联命名空间
- MFC 函数来自 :: 命名空间?
- 使用类指针重载C++命名空间函数模板专用化替代方法?
- 在头文件中添加命名空间函数
- 命名空间函数的多重定义
- 在多个 cpp 文件中重用未命名的命名空间函数
- 如何正确声明命名空间函数
- 使用 libclang 解析命名空间函数
- C++命名空间函数
- 内联命名空间函数时出错
- 递归std::functional与递归匿名命名空间函数.使用哪一个
- 如何在命名空间函数中使用pragma weak