2011-03-02 284 views
4

我在做一个简单的课,使用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

关于你的评论,你需要一个参考返回到您的类,因此您可以链接在一起''<<操作。 – GWW 2011-03-02 18:15:06

回答

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; 
} 

这些将是你定义与MyClass仅有的两个重载operator<<功能。这样,每次调用operator<<时,编译器都会将返回类型从MyClass&切换到MyClass_ExpectInt,反之亦然,并且不允许将“错误”的数据类型传递到operator<<

+2

我会把字符串数据放入临时_ExpectInt中,所以一旦给出了这两个参数,它就只会添加到数组中。 – 2011-03-02 18:23:31

+0

@Pete好点,如果MyInstance <<“First text”;'缺少整数应该什么也不做。这可能更有意义。 – aschepler 2011-03-02 18:29:39

+0

我会使MyClass_ExpectInt的构造函数为私有。因此只有MyClass可以创建对象。我只是这样做,以防止滥用这些对象。 – 2011-03-02 19:21:01

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,它只对int具有运算符< <。和<< int后,返回的引用是唯一具有操作者的MyClass的< <字符串

0

除了什么schepler有说:语法

x << "one" << 1 << "two" << 2; 

并不表明“一”与所属1.今天看起来很好,但明天很难向其他人解释,而且两年内维护人员很难进行反向工程。那是只是因为它类似于'常规'插入运算符,其中确实支持更多类型的

如果你有自由选择你的API的样子,那么现在更好地做一些事情,使其更清楚地表明你真的插入了两个相关的值。

这可以通过例如,只允许std::pair<string,int>被插入:

x << make_pair("one", 1) 
    << make_pair("two", 2) 
    ;