【问题标题】:C++ - ostream, friends and namespacesC++ - ostream、朋友和命名空间
【发布时间】:2012-05-01 22:33:02
【问题描述】:

在我将对象移动到命名空间之前,一切都很好。现在编译器声称我的 Color 属性是私有的。

我认为朋友的全部意义在于与班级的朋友分享封装的信息。

颜色.h

friend ostream & operator << (ostream& output, const st::Color& color);

颜色.cpp:

 ostream & operator <<(ostream& output, const st::Color& color) {

    output << "Colors:\nalpha\t: " << color.a << "\nred\t: "  << color.r << "\ngreen\t: " << color.g
            << "\nblue\t: " << color.b <<  "\nvalue\t: " << color.color();

    return output;
}

错误:

Color.h||In function 'std::ostream& operator<<(std::ostream&, const st::Color&)':|
Color.h|52|error: 'unsigned char st::Color::a' is private|
Color.cpp|15|error: within this context|
Color.h|49|error: 'unsigned char st::Color::r' is private|
Color.cpp|15|error: within this context|
Color.h|51|error: 'unsigned char st::Color::g' is private|
Color.cpp|15|error: within this context|
Color.h|50|error: 'unsigned char st::Color::b' is private|
Color.cpp|16|error: within this context|
||=== Build finished: 8 errors, 0 warnings (0 minutes, 1 seconds) ===|

那么交易是什么? 我使用 Code::Blocks 作为我的 IDE。当我在“颜色”参数上使用点运算符时,它甚至不会显示任何属性或方法。这显然是出事的征兆……某处。

我已经去掉了友元运算符重载,它编译得很好。其他地方没有错误。 什么给了?

声明如下:

namespace st{

class Color {

    friend ostream & operator << (ostream& output, const st::Color& color);
 public:
     ....
 private:
    .....

};
};

编辑:

在我的 CPP 中,我现在已经这样做了:

namespace st{
ostream & st::operator <<(ostream& output, const st::Color& color) {

    output << "Colors:\nalpha\t: " << color.a << "\nred\t: "  << color.r << "\ngreen\t: " << color.g
            << "\nblue\t: " << color.b <<  "\nvalue\t: " << color.color();

    return output;
}
}

st::Color::Color() {

    reset();
}

st::Color::Color(const Color& orig) {

    a = orig.a;
    r = orig.r;
    g = orig.g;
    b = orig.b;
}

void st::Color::reset() {
    a = 0;
    r = 0;
    g = 0;
    b = 0;
}
... etc
}

没有编译错误,但是这种情况在头文件中再次使用命名空间是否正常?或者这完全偏离了我应该做的事情?

编辑: @Rob 也感谢您的意见!

【问题讨论】:

  • “将我的对象移动到命名空间”是什么意思?
  • 在命名空间之间移动对象。 IE 命名空间 st{ 类... }
  • 不要在operator&lt;&lt;的定义中再次使用命名空间。这应该没有必要。
  • 你的意思是不要将定义放在标题中的命名空间中?编辑:对不起,我的意思是 CPP 不是上面代码中的标题。
  • 在 cpp 文件中的 ostream 方法周围添加 st 命名空间声明。请参阅下面的答案(我在 Linux 上使用 g++ 进行了尝试,效果很好)。

标签: c++ overloading ostream


【解决方案1】:

您还需要在与对象相同的命名空间中声明和定义运算符。它们仍然可以通过 Argument-Dependent-Lookup 找到。

通常的实现如下所示:

/// header file
namespace foo {
   class A
   {
    public:
    A();

    private:
    int x_;
    friend std::ostream& operator<<(std::ostream& o, const A& a);
    };

    std::ostream& operator<<(std::ostream& o, const A& a);
} // foo

// cpp file
namespace foo {
     A::A() : x_(23) {}

     std::ostream& operator<<(std::ostream& o, const A& a){
     return o << "A: " << a.x_;
    }
} // foo


int main()
{
  foo::A a;
  std::cout << a << std::endl;
  return 0;
}

编辑

您似乎没有在命名空间中声明 operator&lt;&lt; 并且还在命名空间之外定义它。我已经调整了代码。

【讨论】:

  • 请详细说明。有什么例子吗?到目前为止,朋友是在命名空间 st 中声明的。它在 Color 类中声明。
  • @Sidar 我添加了一个示例。您可能想在问题中添加代码以显示您的问题。
  • 我很困惑,我认为这正是我正在做的事情。声明在 cpp 文件中设置,而定义在标头中。这和你的例子有什么不同?我真的不知道该展示什么。这就是它的全部。
  • 我真的觉得我没有听懂你想告诉我的。声明在对象本身内。然后我在 cpp 中定义它。是否有必要在标题中的名称空间本身中 [再次] 声明它?运算符重载不会成为命名空间的一部分吗?
  • @Sidar 如果你在一个类中声明一个函数为友元,你也隐式地将它声明为周围命名空间中的一个函数。通常最好避免这一切,并有一个公共的 print 函数接受 ostream&amp; 并简单地将周围命名空间中的 operator&lt;&lt; 转发到此函数。
【解决方案2】:

您还需要使用命名空间来限定您的运算符。它是在命名空间中声明的函数签名,因此要访问其符号,您需要在其前面加上命名空间。

试试这样:

namespace st {

    ostream & operator <<(ostream& output, const Color & color) {

        output << "Colors:\nalpha\t: " << color.a
               << "\nred\t: "   << color.r 
               << "\ngreen\t: " << color.g
               << "\nblue\t: "  << color.b
               << "\nvalue\t: " << color.color();

        return output;
    }
}

【讨论】:

  • 抛出我:错误:'std::ostream& st::operator
  • 你用的是什么编译器?这在 Visual Studio Express 2010 中有效。如果这不起作用,那么肯定可以将方法的主体放在命名空间块内的 h 文件中。
  • GCC。这就是我所做的。 (看看我的编辑)所以在标题本身中再次使用命名空间 st{} 会非常好,并且只将运算符重载放在那里?我觉得我错过了这些信息。其他所有内容都只限于 st::Color::Etc。
  • 尝试在您的 cpp 中添加命名空间声明。就像我上面的编辑一样。在 ubuntu VM 上使用 g++ 对我有用。
  • 我的错,我的意思是 CPP。您在上面的编辑中看到的是 CPP 文件。虽然它可以工作,但现在每次我输入 st:: 时,运算符重载也会出现......这是应该的样子吗?
猜你喜欢
  • 2010-12-29
  • 2018-10-20
  • 1970-01-01
  • 2020-12-03
  • 2018-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-13
相关资源
最近更新 更多