【发布时间】:2020-03-20 13:00:37
【问题描述】:
为什么朋友operator<<在cpp文件和using指令中定义时不能被识别?
我在头文件中,game.h
namespace uiuc {
class Game {
public:
Game();
void solve();
friend std::ostream & operator<<(std::ostream & os, Game & game);
private:
std::vector<Stack> stacks;
};
在我的 cpp 文件中,game.cpp:
#include "game.h"
using namespace uiuc;
std::ostream & operator<<(std::ostream & os, Game & game) {
for (unsigned long i = 0; i < game.stacks.size(); ++i) {
os << "Stack [" << i << "]: " << game.stacks[i] << std::endl;
}
return os;
}
我得到的错误是:
g++ -std=c++1z -g -Wfatal-errors -Wall -Wextra -pedantic -MMD -MP -c game.cpp
game.cpp:5:38: fatal error: 'stacks' is a private member of 'uiuc::Game'
for (unsigned long i = 0; i < game.stacks.size(); ++i) {
^
./game.h:17:22: note: declared private here
std::vector<Stack> stacks;
^
1 error generated.
make: *** [Makefile:18: game.o] Error 1
当在头文件中定义友元函数时,这有效。我决定移动它,因为我在同一方法的重复符号上遇到了链接器错误,所以我决定看看如果我将函数定义移动到 cpp 文件会发生什么。我错过了什么?但是,当我将定义包含在 namespace uiuc 中时,它会删除此错误,并且我会返回链接器错误。链接器错误不是这个问题是关于什么的。
为什么编译器不能意识到这是一个友元函数,因此可以访问私有变量?
【问题讨论】:
-
解决方法很简单:只需将您的定义包含在
namespace uiuc {和}中。恕我直言,这很常见。 ;-) 我只相信运算符定义放在全局命名空间中(忽略using namespace uiuc和friend声明)。因此,uiuc::Game中的friend声明是不相关的。 -
您不能使用
using在命名空间中定义函数。如果你有namespace uiuc {void foo();},那么你不能用using namespace uiuc; void foo() {...}定义它 -
如果你想把它保存在头文件中,这意味着停止重复包含警告,只需将函数内联。
-
@heretoinfinity
inline关键字与函数是否内联没有直接关系。inline关键字的实际含义与函数定义是否可以(或必须)在多个翻译单元中重复有关。看我的回答。
标签: c++ header-files friend