访问运算符中的私有类<<在命名空间

时间:2009-08-21 09:24:12

标签: c++ namespaces operator-overloading inner-classes

我有一个带有私有内部类CBar的类CFoo。我想为CFoo实现一个流输出运算符,然后在它的实现中使用CBar的流输出。当CFoo位于公共名称空间中时,我可以使用它,但是当我将它放在新的名称空间(名称空间foobar)中时,运算符无法再访问私有内部类。我怀疑这与运算符的完整签名有关,但我无法弄清楚指定friend声明和实际运算符声明的正确方法,以便实现编译。任何人都可以建议我可能会缺少什么? 请注意,如果流实现是在标头中内联完成的,编译,但我讨厌不必要地公开这样的实现!

在foobar.h中

(只需注释掉usefoobarnamespace以测试非命名空间版本):

#define usefoobarnamespace
#ifdef usefoobarnamespace
namespace foobar
{
#endif // usefoobarnamespace
    class CFoo
    {
    public:
        CFoo() {}
        ~CFoo();
        void AddBar();
    private:
        class CBar
        {
        public:
            CBar() {m_iVal = ++s_iVal;}
            int m_iVal;
            static int s_iVal;
        };

        std::vector<CBar*> m_aBars;

        friend std::ostream& operator<<(std::ostream& rcStream, CFoo& rcFoo);
        friend std::ostream& operator<<(std::ostream& rcStream, CFoo::CBar& rcBar);
    };
    std::ostream& operator<<(std::ostream& rcStream, CFoo& rcFoo);
    std::ostream& operator<<(std::ostream& rcStream, CFoo::CBar& rcBar);
#ifdef usefoobarnamespace
}
#endif // usefoobarnamespace

和foobar.cpp:

#ifdef usefoobarnamespace
using namespace foobar;
#endif // usefoobarnamespace

int CFoo::CBar::s_iVal = 0;


CFoo::~CFoo()
{
    std::vector<CBar*>::iterator barIter;
    for (barIter = m_aBars.begin(); barIter != m_aBars.end(); ++barIter)
    {
        delete (*barIter);
    }
}

void CFoo::AddBar()
{
    m_aBars.push_back(new CBar());
}


std::ostream& operator<<( std::ostream& rcStream, CFoo& rcFoo )
{
    rcStream<<"CFoo(";
    std::vector<CFoo::CBar*>::iterator barIter;
    for (barIter = rcFoo.m_aBars.begin(); barIter != rcFoo.m_aBars.end(); ++barIter)
    {
        rcStream<<(*barIter);   
    }
    return rcStream<<")";
}

std::ostream& operator<<( std::ostream& rcStream, CFoo::CBar& rcBar )
{
    return rcStream<<"CBar("<<rcBar.m_iVal<<")";
}

4 个答案:

答案 0 :(得分:2)

只需将.cpp文件中的代码放入命名空间:

namespace foobar {

// your existing code

}

答案 1 :(得分:2)

您需要将运算符定义显式放在命名空间中。 (或者使用命名空间完全限定它们)。你这样做的方式是声明一些&lt;&lt;运算符(在名称空间foobar中),然后你定义一些全新的&lt;&lt;全局命名空间中的运算符。

namespace foobar
{
    std::ostream& operator<<( std::ostream& rcStream, CFoo& rcFoo )
    {
        rcStream<<"CFoo(";
        std::vector<CFoo::CBar*>::iterator barIter;
        for (barIter = rcFoo.m_aBars.begin(); barIter != rcFoo.m_aBars.end(); ++barIter)
        {
            rcStream<<(*barIter);   
        }
        return rcStream<<")";
    }

    std::ostream& operator<<( std::ostream& rcStream, CFoo::CBar& rcBar )
    {
        return rcStream<<"CBar("<<rcBar.m_iVal<<")";
    }
}

答案 2 :(得分:1)

您的operator<< functions现在位于foobar命名空间中,因此您应将其定义为foobar::operator<<

答案 3 :(得分:0)

可以通过专门化名称空间的流操作符重载来解决该问题:

std::ostream& foobar::operator<<( std::ostream& rcStream, CFoo& rcFoo )
{
    rcStream<<"CFoo(";
    std::vector<CFoo::CBar*>::iterator barIter;
    for (barIter = rcFoo.m_aBars.begin(); barIter != rcFoo.m_aBars.end(); ++barIter)
    {
        rcStream<<(*barIter);   
    }
    return rcStream<<")";
}

std::ostream& foobar::operator<<( std::ostream& rcStream, CFoo::CBar& rcBar )
{
    return rcStream<<"CBar("<<rcBar.m_iVal<<")";
} 

默认情况下,这些函数的全局定义会过载。他们不是CFoo类的朋友,也无法访问其私人成员。