Доступ к закрытому классу в operator << в пространстве имен - PullRequest
0 голосов
/ 21 августа 2009

У меня есть класс CFoo с закрытым внутренним классом CBar. Я хочу реализовать оператор вывода потока для CFoo, который в свою очередь использует вывод потока для CBar в своей реализации. Я могу заставить это работать, когда CFoo находится в общем пространстве имен, но когда я помещаю его в новое пространство имен (пространство имен foobar), оператор больше не может получить доступ к закрытому внутреннему классу. Я подозреваю, что это как-то связано с полной подписью оператора, но я не могу найти правильный способ указать объявление друга и фактическое объявление оператора, чтобы реализация компилировалась. Кто-нибудь может подсказать, чего мне не хватает? Обратите внимание, что будет скомпилироваться, если реализация потока сделана в заголовке inline, но я ненавижу выставлять такую ​​реализацию без необходимости!

в 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 ]

2 голосов
/ 21 августа 2009

Просто поместите код из файла .cpp в пространство имен:

namespace foobar {

// your existing code

}
2 голосов
/ 21 августа 2009

Вам необходимо явно поместить определения операторов в пространство имен. (Или полностью квалифицировать их с пространством имен). Как вы это делаете, вы объявляете некоторые операторы << (которые находятся в пространстве имен foobar), затем вы определяете некоторые совершенно новые операторы << в глобальном пространстве имен. </p>

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<<")";
    }
}
1 голос
/ 21 августа 2009

Ваши operator<< functions теперь находятся в пространстве имен foobar, поэтому вы должны определить их как foobar::operator<<.

0 голосов
/ 21 августа 2009

Проблема может быть решена путем специализированной перегрузки оператора потока для пространства имен:

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 и не могут получить доступ к его частным пользователям.

...