我正在创建一个使用operator<<
的简单类。它将存储两个并行的数据数组,每个数据类型具有不同(但已知)的数据类型。这个想法是最终的界面看起来像这样:
MyInstance << "First text" << 1 << "Second text" << 2 << "Third text" << 3;
这将使数组看起来像这样:
StringArray: | "First text" | "Second text" | "Third text" |
IntArray: | 1 | 2 | 3 |
我可以处理检查输入的逻辑以确保一切都匹配,但我对operator<<
的技术细节感到困惑。
我检查的教程说它将其重载为具有std::ostream&
返回类型的友元函数,但我的类与流无关。我尝试使用void
作为返回类型,但遇到了编译错误。最终我最终返回了对该课程的引用,但我不确定为什么会这样。
到目前为止,这是我的代码:
class MyClass
{
public:
MyClass& operator<<(std::string StringData)
{
std::cout << "In string operator<< with " << StringData << "." << std::endl;
return *this; // Why am I returning a reference to the class...?
}
MyClass& operator<<(int IntData)
{
std::cout << "In int operator<< with " << IntData << "." << std::endl;
return *this;
}
};
int main()
{
MyClass MyInstance;
MyInstance << "First text" << 1 << "Second text" << 2 << "Third text" << 3;
return 0;
}
此外,我班级的用户可以做这样的事情,这是不需要的:
MyInstance << "First text" << 1 << 2 << "Second text" << "Third text" << 3;
我可以做些什么来强制输入的交替性质?
答案 0 :(得分:7)
ostream
运算符返回对ostream
的引用的原因,以及它有助于您的案例返回对MyClass
的引用的原因是A << B << C
这样的表达式总是被解释为(A << B) << C
。也就是说,无论第一个重载操作符返回什么,都会成为下一个操作符调用的左侧。
现在,如果您希望像MyInstance << "First text" << 1 << 2
这样的表达式产生编译器错误,您需要确保在前两个<<
运算符之后返回的类型是一个无法用另一个运算符调用的类型INT。我认为这样的事情可能会做你想要的(感谢@Pete Kirkham的改进主意):
struct MyClass_ExpectInt;
class MyClass {
private:
friend MyClass& operator<<(const MyClass_ExpectInt&, int);
void insert_data(const std::string& StringData, int IntData);
// ...
};
struct MyClass_ExpectInt {
MyClass& obj_ref;
std::string str_data;
explicit MyClass_ExpectInt( MyClass& obj, const std::string& str )
: obj_ref( obj ), str_data( str ) {}
};
MyClass_ExpectInt operator<<( MyClass& obj, const std::string& StringData )
{
// Do nothing until we have both a string and an int...
return MyClass_ExpectInt( obj, StringData );
}
MyClass& operator<<( const MyClass_ExpectInt& helper, int IntData )
{
helper.obj_ref.insert_data( helper.str_data, IntData );
return helper.obj_ref;
}
这些是您定义的与operator<<
相关的唯一两个重载MyClass
函数。这样,每次调用operator<<
时,编译器都会将返回类型从MyClass&
切换到MyClass_ExpectInt
,反之亦然,并将“错误”类型的数据传递给{{1绝不允许。
答案 1 :(得分:2)
MyInstance << "First text" << 1;
此行调用operator<<(operator<<(MyInstance, "First text"), 1)
。如果operator<<
未返回对MyClass
的引用,则“外部”调用将失败,因为您将在预期MyClass &
的位置传递void。
为了强制执行交替类型的编译时,你需要创建一个帮助类,例如MyClassHelper。然后,您需要创建这两个运算符:
MyClassHelper & operator<<(MyClass &, std::string const &);
MyClass & operator<<(MyClassHelper &, int);
然后,每个运算符都应该返回对“其他”所涉及对象的引用。这确保在<< "string"
之后返回的引用是MyClassHelper,它只有一个运算符&lt;&lt;对于int。在<< int
之后,返回的引用是一个MyClass,它只有一个运算符&lt;&lt;用于字符串
答案 2 :(得分:0)
除了schepler所说的内容:语法
x << "one" << 1 << "two" << 2;
没有表明“一个”属于1.今天看起来很好,但明天很难向其他人解释,而且两年内维护人员更难对其进行逆向工程。那是因为它类似于'常规'插入操作符, 支持更多类型。
如果您可以自由选择API的外观,那么现在最好先做一些事情,以便更清楚地知道您真正插入了两个相关值。
这可以通过例如仅允许插入std::pair<string,int>
:
x << make_pair( "one", 1 )
<< make_pair( "two", 2 )
;