2012-03-23 4 views
2

operator<<을 포인터로 호출 할 때 문제가 있습니다. 나는 SO를 통해 검색 한 후 Google에서 내 질문을했지만 제안 된 모든 해결책이 내 문제를 해결하지 못했습니다.오버로드 된 std :: ostream 연산자 << 호출되지 않음, 스트림이 객체 대신 변수 주소를 가져옵니다.

Marker.h :

class Marker { 
    ... 
public: 
    friend std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    friend std::ostream& operator<<(std::ostream& out, Marker* marker); 
}; 

inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { 
     out << "Marker " << marker._name << " of type " << marker._type << " at position " << marker._position; 
     return out; 
} 

inline std::ostream& operator<<(std::ostream& out, Marker* marker) { 
     out << *marker; 
     return out; 
} 

Landmark.h :

class Landmark { 
     ... 
     Marker* m_marker; 
     ... 
}; 

Landmark.cpp 내 문제를 설명하기 위해, 내 코드의 단순화 된 부분을 참조하십시오

void Landmark::print(std::ostream& out) 
{ 
    out << "Marker GENERIC: " << m_marker << std::endl; 
    //out << "Marker GENERIC: " << *m_marker << std::endl; 
} 

Visual Studio 2008에서이 링크가 나타나지 않습니다. unresolved external symbol 오류가 발생합니다. friend std::ostream& operator<<(std::ostream& out, Marker* marker);을 제거하면 코드가 컴파일되지만 예상되는 형식화 된 출력 대신 마커 Marker* Landmark::m_marker에 대한 포인터의 메모리 주소 만 표시됩니다. 두 번째 줄 주석 처리를 제거하면 코드가 호환되지 않습니다.

올바른 출력을 얻으려면 operator<<을 어떻게 오버로드해야합니까?

어떤 도움을 주셔서 감사합니다.

+0

참고 : 포인터 과부하, 두 가지가 누락되었습니다. 'Marker' 인스턴스는 어떤 식 으로든 변형되지 않기 때문에'Marker const * marker'를 읽어야합니다; 그리고 경우에 따라서는 ''을 출력 할 것입니다. –

+0

'std :: ostream & operator << (std :: ostream & out, Marker * marker)'를 자신의 컴파일 유닛 (즉, .cpp 파일)에서 (비 - 인라인) 함수로 정의하려고하면 링커를 행복하게 만드는가? –

+0

컴파일러는 논쟁하지 않지만이 DLL을 포함하는 프로젝트는'std :: ostream & operator << (std :: ostream & out, Marker * marker)'함수에서'unresolved external symbol'을 컴파일하지 않습니다. 이 함수가 전역 이름 공간에 정의되어야합니까? 내 경우에는 모든 클래스와 오버로드 된 연산자 함수가 내 네임 스페이스 안에 있습니다. –

답변

2

out << *m_marker;은 간단한 예입니다 :

#include <iostream> 

namespace mine { 
class Marker { 
public: 
    friend std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    friend std::ostream& operator<<(std::ostream& out, Marker* marker); 
}; 

inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { 
    out << "Marker"; 
    return out; 
} 

inline std::ostream& operator<<(std::ostream& out, Marker* marker) { 
    out << *marker; 
    return out; 
} 
} // namespace mine 

int main() { 
    mine::Marker marker; 
    mine::Marker* m = &marker; 

    std::cout << m << "\n"; 
} 

그리고 as expected 작동합니다.

당신이 가리키는 오류는 링커 오류입니다. 컴파일러가 함수가 생성되지 않은 메서드에 대한 호출을 생성했음을 알려줍니다.

나는 당신이 우리에게 거짓말을했거나 Visual Studio가 다시 한 번 잘못되었다고 생각합니다.

  • 당신이 거짓말을하는 경우 (즉, 정확한 코드를 복사하지 않았다) : inline 방법을 definining 때, 전체 메소드 본문이 포함되어야주의를 사용하기 전에 따라서 Landmark.cpp는 방법 정의를 포함해야한다 .
  • 또는 VS를 도우 전에 함수를 미리 선언하여 VS가 자신이네임 스페이스에 있고 글로벌 네임 스페이스에 살고 있음을 이해할 수 있도록해야 할 수도 있습니다. 같은

뭔가 :

namespace mine { 
    class Marker; 

    std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    std::ostream& operator<<(std::ostream& out, Marker* marker); 

    class Marker { 
    public: 
    friend std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    friend std::ostream& operator<<(std::ostream& out, Marker* marker); 
    }; 

    inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { 
    out << "Marker"; 
    return out; 
    } 

    inline std::ostream& operator<<(std::ostream& out, Marker* marker) { 
    out << *marker; 
    return out; 
    } 
} // namespace mine 
+0

답장을 보내 주셔서 감사합니다. 함수가 로컬 네임 스페이스에 있다는 것을 컴파일러에게 설명하는 두 번째 트릭이 효과가있다. 문제는 아마도 operator << 내 다른 객체에 << 연산자를 호출했기 때문에 같은 오류가 두 번 발생했기 때문에 추적하기가 더 어려웠습니다. –

+0

@PavloDyban : VS2003 (메모리가 올바르게 작동하는 경우)에서이 버그가 있었으며 "재귀"와 관련이 없습니다. 일반적으로 'friend' 선언은 클래스의 네임 스페이스에 선언 된 함수를 도입해야하지만, 이전 선언이 없으면 VS가 발생하는 것으로 보입니다. 표준이 명시하고 있는지 여부는 확실하지 않습니다. (그리고 나는 그것이 버그라고 생각합니다.) –

0

는 변경이

friend std::ostream& operator<<(std::ostream& out, Marker* marker); 

friend std::ostream& operator<<(std::ostream& out, Marker marker); 

으로

그리고 당신이 실제 개체를 전달하는 동안이

out << "Marker GENERIC: " << *m_marker << std::endl; 

귀하의 출력 연산자는 포인터를 기다리고 있었다 사용합니다.

+1

마커가 구현되는 방법에 따라 값으로 전달하는 것이 좋지 않을 수 있습니다. 아마도 마커 마커 대신 스트리밍 연산자 인'const 마커 및 마커 '를 두 번째 인수로 만드는 것이 좋습니다. –

+0

댓글을 주셔서 감사합니다. 포인터로 오버로드를 인수로 숨기고 대신 참조 포인터를 사용했습니다. 이는 마커를 값으로 전달하여 제안한 것과 거의 같습니다. 그러나'out << "줄에 별표가 없기를 바란다. Marker GENERIC :"<< * m_marker << std :: endl;'. 연산자를 오버로딩하여 'Marker'에 대한 포인터를 가져 와서 객체의 내용을 출력해야합니까? –

1

바로 지금 개체에 대한 포인터와 참조를 모두 오버로드 할 수 있습니다. 포인터를 전달하고 있으므로 참조를 사용하는 오버로드가 사용되지 않습니다.

포인터를 취하는 오버로드를 없애고 참조를 취하는 오버로드를 사용합니다. 포인터를 역 참조하여 사용 여기

+0

감사합니다! 너는 나에게 올바른 충고를 했어! 이제 마커 GENERIC : << << m_marker << std :: endl;'행을 떠나고 싶다면, 마커 객체의 주소를 전달하는 방법으로'operator <<'를 오버로드해야합니까? ? –