C++ 在operator中访问私有类<&书信电报;在命名空间中
我有一个类CFoo和一个私有的内部类CBar。我想为CFoo实现一个stream-output操作符,它反过来在实现中使用CBar的流输出。当CFoo位于公共名称空间中时,我可以实现这一点,但当我将其放置在新名称空间(名称空间foobar)中时,操作符将无法再访问私有内部类。我怀疑这与运算符的完整签名有关,但我无法找到正确的方法来指定友元声明和实际运算符声明,以便编译实现。有人能告诉我可能遗漏了什么吗? 请注意,如果流实现是在头中内联完成的,那么它将被编译,但我讨厌不必要地公开这样的实现 在foobar.h中(只需注释掉usefoobarnamespace以测试非命名空间版本):C++ 在operator中访问私有类<&书信电报;在命名空间中,c++,namespaces,operator-overloading,inner-classes,C++,Namespaces,Operator Overloading,Inner Classes,我有一个类CFoo和一个私有的内部类CBar。我想为CFoo实现一个stream-output操作符,它反过来在实现中使用CBar的流输出。当CFoo位于公共名称空间中时,我可以实现这一点,但当我将其放置在新名称空间(名称空间foobar)中时,操作符将无法再访问私有内部类。我怀疑这与运算符的完整签名有关,但我无法找到正确的方法来指定友元声明和实际运算符声明,以便编译实现。有人能告诉我可能遗漏了什么吗? 请注意,如果流实现是在头中内联完成的,那么它将被编译,但我讨厌不必要地公开这样的实现 在fo
#定义usefoobarnamespace
#ifdef usefoobarnamespace
名称空间foobar
{
#endif//usefoobarnamespace
类CFoo
{
公众:
CFoo(){}
~CFoo();
void AddBar();
私人:
类CBar
{
公众:
CBar(){m_iVal=++s_iVal;}
国际货币基金组织;
静态整数;
};
std::向量m_aBars;
friend std::ostream&operator您的operator您的operator只需将.cpp文件中的代码放入命名空间:
namespace foobar {
// your existing code
}
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<<")";
}
只需将.cpp文件中的代码放入命名空间:
namespace foobar {
// your existing code
}
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<<")";
}
您需要将运算符定义显式地放在命名空间中。(或使用命名空间完全限定它们)。执行此操作的方式是声明一些,您需要将运算符定义显式地放在命名空间中。(或使用命名空间完全限定它们)。您这样做的方式是声明一些,可以通过专门化命名空间的流运算符重载来解决此问题:
namespace foobar {
// your existing code
}
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<<")";
}
std::ostream&foobar::operator可以通过专门化命名空间的流运算符重载来解决此问题:
namespace foobar {
// your existing code
}
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<<")";
}
std::ostream&foobar::operator通常这适用于CFoo操作符,但不适用于CFoo::CBar one。std::ostream&foobar::operator@FlintZA:奇怪,对我有用,我在回答(g++4.3.3)之前编译了它。你能再检查一下吗?顺便说一下,我在你的代码中发现了一个可能的错误,在(*barIter)您可能希望取消引用两次(*(*barIter))为了调用CBar重载运算符。@UncleZiev Well Cougt:)在我的实际代码案例中,内部类对象实际上在映射中,所以我取消引用。其次,在转换为更简单的测试案例时,我错过了这一点。至于此解决方案不编译,我使用Visual Studio 2008编译,所以我认为这是MS c的一个怪癖ompiler不是第一个;)奇怪的是,这对CFoo操作符有效,但对CFoo::CBar one.std::ostream&foobar::operator@FlintZA:奇怪,对我有用,我在回答(g++4.3.3)之前编译了它。你能再检查一下吗?顺便说一下,我在你的代码中发现了一个可能的错误,在(*barIter)中,你可能想取消引用两次(*(*barIter))以便调用CBar重载运算符。@UncleZiev Well-Cougt:)在我实际的代码案例中,内部类对象实际上在一个映射中,所以我正在取消引用。其次,我在转换到更简单的测试用例时错过了这一点。至于这个解决方案,我没有编译,我是用Visual Studio 2008编译的,所以我想这是MS编译器的一个怪癖,不会是第一个;)谢谢,这确实有效。我宁愿不包装cod如果我能帮助的话,我会在名称空间中的实现文件中这样做,但如果我找不到另一个可行的解决方案,我会只为运算符这样做。+1我从来都不明白为什么人们在定义名称空间中的函数/方法时会使用using指令。@FlintZA愿意分享一下这种特殊偏好的原因吗?这是使用名称空间的最简单、最干净的方法。@Neil我们使用的是全番茄(非常好)可视化辅助。它的一个重构工具允许您为函数定义自动创建一个实现。这个自动生成的实现签名包括名称空间,因此使用上述方法需要对代码进行更多的手动修剪。谢谢,这确实有效。我不希望在我的实现中包装代码如果我能帮助的话,我会在名称空间中创建类似这样的文件,但如果我找不到另一个可行的解决方案,我只会为运算符这样做。+1我从来都不明白为什么人们在定义名称空间中的函数/方法时会使用using指令。@FlintZA愿意分享这种特殊偏好的原因吗?这是最简单的,最干净的名称空间使用方式。@Neil我们使用的是全番茄(非常好)可视化辅助。它的一个重构工具允许您自动创建函数定义的实现。此自动生成的实现签名包括名称空间,因此使用上述方法将需要更多的手动修剪代码。我对Niel的回答同上:)我对Niel的回答同上:)