为命名空间内定义的类重载ostream运算符(<<<<<<<

时间:2015-02-25 04:27:32

标签: c++ namespaces operator-overloading ostream

考虑 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;
}

为什么运算符&lt;&lt; 的实现无法从 Bar 类访问私有成员?那就是:

$ 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 命名空间中嵌入运算符&lt;&lt; 的实现来解决问题,即:

namespace foo {
std::ostream& operator<<(std::ostream& output, const foo::Bar &in) {

  output << in.xx_ << std::endl;

  return output;
}
}

然而......这是解决这个问题的正确方法吗?这种方法不是提供实施细节吗?

2 个答案:

答案 0 :(得分:7)

问题:

  

这是解决这个问题的正确方法吗?

答案:

  

是的,这是解决问题的正确方法。

问题:

  

这种方法是否提供了实施细节?

答案:

  

完全没有。

该行

friend std::ostream& operator <<(std::ostream& output, const Bar&);

将函数声明为定义类的命名空间中的外部函数。如果未在命名空间中定义类,则将该函数声明为全局命名空间中的外部函数。由于函数在foo命名空间中被声明为外部函数,因此必须在该命名空间中定义。

如果您希望该函数成为全局函数,在foo namesapce之外,您必须使用:

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_;
   };
}

答案 1 :(得分:2)

因为您的类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;
}

}