プライベート内部クラス CBar を持つクラス CFoo があります。CFoo のストリーム出力演算子を実装したいと思います。これは、その実装で CBar のストリーム出力を使用します。CFoo が共通の名前空間にある場合はこれを機能させることができますが、新しい名前空間 (名前空間 foobar) に配置すると、オペレーターはプライベート内部クラスにアクセスできなくなります。これは演算子の完全な署名と関係があると思われますが、実装がコンパイルされるようにフレンド宣言と実際の演算子宣言を指定する正しい方法がわかりません。誰かが私が見逃している可能性があるものを提案できますか? ストリームの実装がヘッダーでインラインで行われている場合はコンパイルされることに注意してください。ただし、このような実装を不必要に公開するのは嫌いです。
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<<")";
}