Accessing a Private Class in the << Operator in a Namespace
I have a CFoo class with a private inner CBar class. I want to implement a stream output operator for CFoo, which in turn uses a stream for CBar in the implementation. I can get this to work when CFoo is in a shared namespace, but when I put it in a new namespace (namespace foobar) the operator can no longer access the private inner class. I suspect it has something to do with the full operator signature, but I cannot figure out the correct way to specify the friend declaration and the actual operator declaration so that the compilation is done. Can anyone suggest what I might be losing? Note that it will compile if the stream implementation is made inline in the header, but I don't like exposing the implementation as overkill!
in foobar.h (just comment out usefoobarnamespace to check non-name version):
#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
and in 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<<")"; }
source share
You must explicitly list operator definitions in the namespace. (Or fully qualify them with a namespace). As you do this, you declare some <operators (which are in the foobar namespace), then you define some completely new <operators in the global namespace.
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<<")"; } }
source share
This problem can be solved by specializing in namespace overloading of the stream operator:
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<<")"; }
By default, the global definitions of these functions are overloaded. They are not friends of the CFoo class and cannot access their private members.
source share