2010-01-22 20 views
2

다음 코드가 컴파일되지 않는 이유를 알 수 없습니다. 구문은 다른 연산자 오버로드와 같습니다. < < 과부하가 필요하다는 제한이 있습니까? 그렇다면 왜? 어떤 도움을 주셔서 감사합니다.왜 이렇게하지 않습니까? << 과부하 컴파일

이 작동하지 않습니다 - 최초의 형태가 temp << std::cout 과부하 때문에

#include "stdafx.h" 
#include <iostream> 
#include <fstream> 
#include <string> 

class Test 
{ 
public: 
explicit Test(int var): 
    m_Var(var) 
    { } 

    friend std::ostream& operator<< (std::ostream& stream, Test& temp); 

private: 
    int m_Var; 

}; 

std::ostream& operator<< (std::ostream& stream, Test& temp) 
{ 
return stream << temp.m_Var; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
Test temp(5); 

std::cout << temp; 

return 0; 
} 
+0

물론 이것은 속임수입니다. http://stackoverflow.com/questions/236801/should-operator-be-implemented-as-a-friend-or-as-a-member-function, 예를 들어 –

+0

@ Neil 인 경우, Google에서이 답변에 대한 높고 낮음을 검색하여 찾을 수 없습니다. 친구와 함께 구현하는 방법이 궁금하지 않았지만, 왜 처음에는 구현할 수 없었습니다. – Steve

답변

4

다음은 스트림 운영자가 친구 여야하는 근본적인 이유입니다.

이 코드를 가지고 :

cout.operator<<(g); 

... 그리고 그 ISN 경우 '컴파일러는이 기능을 컴파일 할 때

struct Gizmo 
    { 
     ostream& operator<<(ostream& os) const 
     { 
      os << 42; 
     } 
    }; 


    int main() 
    { 
     Gizmo g; 
     cout << g; 
     return 0; 
    } 

cout << g;에 대한 호출의 컨텍스트를 고려를 먼저이 시도 t를 찾으면 전역 네임 스페이스에서 다음을 찾습니다.

operator<<(cout, g); 

... 찾을 수 없으면 컴파일 할 수 없습니다.

하지만 기즈모의 구성원으로 스트림 삽입 연산자를 구현하려고하면 컴파일러가 코드를 해결할 희망하고있다 : 당신은 변경하지 않는 한 할 수없는

g.operator<<(cout); 

... 귀하의 코드 :

g << cout; 

... 분명히 당신이 무엇을 하려는지는 아닙니다.

6

-

#include "stdafx.h" 
#include <iostream> 
#include <fstream> 
#include <string> 

class Test 
{ 
public: 
explicit Test(int var): 
    m_Var(var) 
    { } 

    std::ostream& operator<< (std::ostream& stream) 
    { 
     return stream << m_Var; 
    } 
private: 
int m_Var; 

}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
Test temp(5); 

std::cout << temp; 

return 0; 
} 

이 작업을 수행합니다.

9

모든 연산자는 "friend ed"여야합니다. 문제는 연산자를 인스턴스 메소드로 선언하면 첫 번째 인수는 항상 클래스 자체의 유형이되어야한다는 것입니다. 이 경우 연산자 (왼쪽)의 첫 번째 매개 변수가 std::ostream&이어야하므로 인스턴스 메서드를 사용하여 오버로드 할 수 없으므로 전역 함수를 사용해야합니다.

한편, 별도의 함수로 선언 된 연산자는 friend 함수로 선언 할 필요가 전혀 없습니다. 그들은 public 그들의 인자들에 접근하기 만하면 클래스의 friend이되지 않고 행복하게 일할 수 있습니다.

+0

다른 운영자에 대해서는 스트리밍 운영자에게 특별한 규칙이 있다는 것을 알지 못했습니다. – Steve

+0

@ 스티브 : '<<' and '>>'에 대한 특별한 것은 없습니다.이것들은 기본적으로 C++ 라이브러리의 스트림 클래스에 오버로드 된 비트 단위 시프트 연산자입니다. –

3

멤버 함수로 구현 될 때 연산자 오버로드에는 이되는 암시 적 첫 번째 매개 변수가 있습니다. 스트림의 경우 이것은 순서가 맞지 않습니다. 스트림이 먼저 와야합니다.

친구 연산자를 사용하면 짧고 간결하며 원하지 않는 암시 적 변환 (ADL을 통해서만 사용되기 때문에)을 방지 할 수 있습니다.

struct T { 
    template<class Ch, class Tr> 
    friend 
    std::basic_ostream<Ch, Tr>& operator<<(
    std::basic_ostream<Ch, Tr>& s, 
    T const& v 
) { 
    s << v.stuff; // or call v.output(s), etc. 
    return s; 
    } 

private: 
    int stuff = 0; // initialization here is c++0x only 

    //virtual void output(std::ostream&) const; 
    //virtual void output(std::wostream&) const; 
    // etc., or make it a template, but if it's short, 
    // just put it in the above friend overload 
}; 

보너스 포인트 : 이름 운영자 과부하 당신이 그것을 정의하려면 아웃 오브 라인 (구현 .cpp 파일에서 예), 다음은 비공개 가능성이 가상 메소드를 호출 한 이없는 회원은입니다. (힌트 : 그들은 정적있어.) 유효 C에서 스콧 마이어스에 의해 요약 된 바와 같이

0

++ 2 판 항목 19 : 멤버 함수, 비 멤버 함수 및 친구 기능들 사이에서 차별화 :

연산자 >>와 운영자 < <은 절대 회원이 아닙니다. f가 연산자 >> 또는 연산자 < <이면 f 멤버가 아닌 함수로 만듭니다. 또한 f가 C의 비공개 회원에게 액세스해야하는 경우 f를 C의 친구로 지정하십시오.

이 문은 교환 원을 < < 및 연산자 >> 회원으로 만들 것인지 여부를 결정하기위한 지침 일뿐입니다. 그들을 비회원으로하는 것이 가장 좋습니다. 당신은 당신이 좋아하는 경우에 그 회원 수 있지만, 당신이 한 경우에, 당신은 쓸 강제 될 것이다 : 당신은 실제로 수 std 전화를 변경 :: cout을을 위의 양식에 의해 코드의 첫 번째 부분을 정정 할 수

temp << std::cout // when calling operator<< 
temp >> std::cin // when calling operator>> 

. 그러나이 글쓰기 방법은 당연히 자연스럽지 않습니다.

오퍼레이터 (비회원)에 대한 프렌딩에 관해서는 두 명의 운영자가 개인/보호 된 데이터 멤버에 액세스해야하는 경우 (해당 경우) 클래스 외부의 친구 여야합니다.

+0

음, 다소 오해의 소지가 있습니다. 그것들은 허용되지 않았기 때문에 멤버 함수가 아닙니다. 나쁜 생각이 아니기 때문이 아닙니다. 나는 그 (것)들을 주변에 얻기 위하여 그 (것)들을 친구가되어야한다. – Steve

+1

d/v로 가지 않겠지 만 "* 왜 * 친구가 될 수 밖에 없는가?"라는 질문에 대답하지 않습니다. –

+0

다른 답변은 아마도 더 명확 할 것입니다 ... 그러나 나는 그것이 가치있는 것에 대한 설명을 추가했습니다;) – Yukiko

3

std::cout << temp;을 수행 할 때 이것은 << 연산자를 std::cout에 적용한다는 것을 의미합니다 (연산자는 연관 적으로 남아 있기 때문에). 이를 달성하기위한 멤버 함수 인 연산자를 작성하려면 std::cout 클래스에 속하는 연산자에 << 연산자를 오버로드해야합니다. 이는 수정할 수없는 것이므로 불가능합니다.

그래서 가능한 한 기능을 작성해야합니다. 하나의 방법은 콘솔에 표시 할 객체와 스트림이라는 두 개의 인수를 취하는 글로벌 네임 스페이스의 오버로드 <<입니다. 이

std::ostream& operator<< (std::ostream& stream, Test& temp)

같은 지금 당신은 친구 여부를 만들 수 중 하나. 친구로 만들지 않으면 클래스의 값을 제공하는 getter 함수 (예 : getMVar)를 제공해야합니다. 그러나 이것은 좋은 접근 방법이 아닙니다. 이 때문에 불필요하게 getter 함수를 제공 할 필요가 있습니다. 그런 사업자들을 친구로 만드는 것은 일반적으로 관습입니다.

이전에 지적했듯이, 코드를이 temp << std::cout으로 작성하게 만드는 것은 분명히 원하는 것이 아닙니다.