2011-03-02 16 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

답변

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에 넣으므로 두 매개 변수를 모두 입력하면 배열에 추가됩니다. –

+0

@Pete 'MyInstance << "첫 번째 텍스트";가 누락 된 정수가있는 좋은 점은 아무 것도 수행하지 않아야합니다. 그리고 아마 더 의미가 있습니다. – aschepler

+0

나는 MyClass_ExpectInt의 생성자를 private으로 만들 것이다. 따라서 MyClass만이 객체를 생성 할 수 있습니다. 나는 객체의 오용을 막기 위해이 작업을 수행 할 것입니다. –

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. 오늘 당신에게보기 좋지만, 내일 다른 사람에게 설명하기가 매우 어려울 것이며, 2 년 내에 관리자가 리버스 엔지니어링하기가 더 어려워 질 것입니다. 인데은 '일반'삽입 연산자와 비슷하기 때문에 이 더 많은 유형을 지원합니다.

API의 모양을 자유롭게 선택할 수 있다면 지금 실제로 두 가지 연관된 값을 삽입하고 있음을 명확히하기 위해 더 나은 것을 수행하십시오.

이것은 예를 들어,

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