为命名空间中定义的 class 重载 ostream 运算符 (<<)
Overloading ostream operator (<<) for class defined within a namespace
考虑 bar.h:
#include <iostream>
namespace foo {
class Bar {
public:
friend std::ostream& operator <<(std::ostream& output, const Bar&);
private:
int xx_;
};
}
考虑 bar.cc:
#include "bar.h"
std::ostream& operator<<(std::ostream& output, const foo::Bar &in) {
output << in.xx_ << std::endl;
return output;
}
为什么 operator << 的实现无法从 Bar class 访问私有成员?即:
$ icpc -c bar.cc
bar.cc(5): error #308: member "foo::Bar::xx_" (declared at line 9 of "bar.h") is inaccessible
output << in.xx_ << std::endl;
^
compilation aborted for bar.cc (code 2)
我通过在 foo 命名空间中嵌入 operator << 的实现解决了这个问题,即:
namespace foo {
std::ostream& operator<<(std::ostream& output, const foo::Bar &in) {
output << in.xx_ << std::endl;
return output;
}
}
然而...这是解决这个问题的正确方法吗?这种做法不是泄露了实现的细节吗?
问题:
is this the correct way of solving this problem?
答案:
Yes, it is the correct way of solving the problem.
问题:
Isn't this approach giving away details of the implementation?
答案:
Not at all.
行
friend std::ostream& operator <<(std::ostream& output, const Bar&);
在定义 class 的命名空间中将函数声明为外部函数。如果 class 未在命名空间中定义,则该函数在全局命名空间中被声明为外部函数。由于该函数在 foo
命名空间中被声明为外部函数,因此它 必须 在该命名空间中定义。
如果你想让那个函数成为一个全局函数,在 foo
命名空间之外,你必须使用:
namespace foo
{
class Bar;
}
std::ostream& operator <<(std::ostream& output, const foo::Bar&);
namespace foo {
class Bar {
public:
friend std::ostream& operator <<(std::ostream& output, const Bar&);
private:
int xx_;
};
}
因为您的 class Bar 是 foo 命名空间的一部分,您需要在同一命名空间中定义该函数。
如果您担心隐藏实现细节,您仍然可以在 bar.cc
中定义函数
bar.cc
#include "foo.h"
namespace foo
{
std::ostream& operator<<(std::ostream& output, const Bar &in)
{
output << "Bar x=" << in.x << std::endl;
return output;
}
}
考虑 bar.h:
#include <iostream>
namespace foo {
class Bar {
public:
friend std::ostream& operator <<(std::ostream& output, const Bar&);
private:
int xx_;
};
}
考虑 bar.cc:
#include "bar.h"
std::ostream& operator<<(std::ostream& output, const foo::Bar &in) {
output << in.xx_ << std::endl;
return output;
}
为什么 operator << 的实现无法从 Bar class 访问私有成员?即:
$ icpc -c bar.cc
bar.cc(5): error #308: member "foo::Bar::xx_" (declared at line 9 of "bar.h") is inaccessible
output << in.xx_ << std::endl;
^
compilation aborted for bar.cc (code 2)
我通过在 foo 命名空间中嵌入 operator << 的实现解决了这个问题,即:
namespace foo {
std::ostream& operator<<(std::ostream& output, const foo::Bar &in) {
output << in.xx_ << std::endl;
return output;
}
}
然而...这是解决这个问题的正确方法吗?这种做法不是泄露了实现的细节吗?
问题:
is this the correct way of solving this problem?
答案:
Yes, it is the correct way of solving the problem.
问题:
Isn't this approach giving away details of the implementation?
答案:
Not at all.
行
friend std::ostream& operator <<(std::ostream& output, const Bar&);
在定义 class 的命名空间中将函数声明为外部函数。如果 class 未在命名空间中定义,则该函数在全局命名空间中被声明为外部函数。由于该函数在 foo
命名空间中被声明为外部函数,因此它 必须 在该命名空间中定义。
如果你想让那个函数成为一个全局函数,在 foo
命名空间之外,你必须使用:
namespace foo
{
class Bar;
}
std::ostream& operator <<(std::ostream& output, const foo::Bar&);
namespace foo {
class Bar {
public:
friend std::ostream& operator <<(std::ostream& output, const Bar&);
private:
int xx_;
};
}
因为您的 class Bar 是 foo 命名空间的一部分,您需要在同一命名空间中定义该函数。
如果您担心隐藏实现细节,您仍然可以在 bar.cc
中定义函数bar.cc
#include "foo.h"
namespace foo
{
std::ostream& operator<<(std::ostream& output, const Bar &in)
{
output << "Bar x=" << in.x << std::endl;
return output;
}
}