아
#include "logic.h"
...
class A
{
friend ostream& operator<<(ostream&, A&);
...
};
logic.cpp
#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...
컴파일하면 다음과 같이 표시됩니다.
std :: ostream & logic :: operator << (std :: ostream &, A &) ‘는 정확히 하나의 인수를 가져야합니다.
무엇이 문제입니까?
답변
문제는 클래스 내부에서 정의한다는 것입니다.
a) 두 번째 인수가 암시 적 ( this
)이고
b) 원하는 것을 수행하지 않습니다 std::ostream
.
자유 함수로 정의해야합니다.
class A { /* ... */ };
std::ostream& operator<<(std::ostream&, const A& a);
답변
친구 함수는 멤버 함수가 아니기 때문에 문제는 다음 operator<<
의 친구로 선언한다는 것 입니다 A
.
friend ostream& operator<<(ostream&, A&);
그런 다음 클래스의 멤버 함수로 정의하십시오. logic
ostream& logic::operator<<(ostream& os, A& a)
^^^^^^^
logic
클래스인지 네임 스페이스 인지 혼란 스럽 습니까?
오류는 operator<<
두 개의 인수 를 사용하는 멤버를 정의하려고했기 때문에 암시 적 this
매개 변수를 포함하여 세 개의 인수를 사용합니다 . 연산자는 두 개의 인수 만 사용할 수 있으므로 작성 a << b
시 두 개의 인수는 a
및 b
입니다.
당신은 정의 할 ostream& operator<<(ostream&, const A&)
A와 비 – 구성원 기능, 확실히의 구성원으로 logic
는 그 클래스와는 아무 상관이 없기 때문에!
std::ostream& operator<<(std::ostream& os, const A& a)
{
return os << a.number;
}
답변
템플릿 클래스에서이 문제가 발생했습니다. 다음은 내가 사용해야하는보다 일반적인 솔루션입니다.
template class <T>
class myClass
{
int myField;
// Helper function accessing my fields
void toString(std::ostream&) const;
// Friend means operator<< can use private variables
// It needs to be declared as a template, but T is taken
template <class U>
friend std::ostream& operator<<(std::ostream&, const myClass<U> &);
}
// Operator is a non-member and global, so it's not myClass<U>::operator<<()
// Because of how C++ implements templates the function must be
// fully declared in the header for the linker to resolve it :(
template <class U>
std::ostream& operator<<(std::ostream& os, const myClass<U> & obj)
{
obj.toString(os);
return os;
}
이제 : * 내 toString () 함수가 cpp에 들어가면 인라인 될 수 없습니다. * 헤더에 일부 코드가있어 제거 할 수 없습니다. * 연산자는 인라인되지 않은 toString () 메서드를 호출합니다.
operator <<의 본문은 friend 절 또는 클래스 외부에서 선언 할 수 있습니다. 두 옵션 모두 추악합니다. 🙁
오해하거나 뭔가 빠졌을 수도 있지만 연산자 템플릿을 앞으로 선언하면 gcc에서 링크되지 않습니다.
이것도 작동합니다.
template class <T>
class myClass
{
int myField;
// Helper function accessing my fields
void toString(std::ostream&) const;
// For some reason this requires using T, and not U as above
friend std::ostream& operator<<(std::ostream&, const myClass<T> &)
{
obj.toString(os);
return os;
}
}
operator <<를 구현하기 위해 템플릿 화되지 않은 부모 클래스를 사용하고 가상 toString () 메서드를 사용하면 헤더에서 선언을 강제하는 템플릿 문제를 피할 수 있다고 생각합니다.
답변
operator<<
멤버 함수로 정의 하면 비 멤버를 사용한 경우와는 다른 분해 구문을 갖게됩니다 operator<<
. 비 멤버 operator<<
는 멤버 operator<<
가 단항 연산자 인 이항 연산자입니다.
// Declarations
struct MyObj;
std::ostream& operator<<(std::ostream& os, const MyObj& myObj);
struct MyObj
{
// This is a member unary-operator, hence one argument
MyObj& operator<<(std::ostream& os) { os << *this; return *this; }
int value = 8;
};
// This is a non-member binary-operator, 2 arguments
std::ostream& operator<<(std::ostream& os, const MyObj& myObj)
{
return os << myObj.value;
}
그래서 .. 진짜 어떻게 부르나요? 연산자는 어떤면 operator<<(...)
에서 이상합니다. 이해를 돕기 위해 머리 속에 구문 을 작성하도록 도전하겠습니다 .
MyObj mo;
// Calling the unary operator
mo << std::cout;
// which decomposes to...
mo.operator<<(std::cout);
또는 멤버가 아닌 이항 연산자를 호출 할 수 있습니다.
MyObj mo;
// Calling the binary operator
std::cout << mo;
// which decomposes to...
operator<<(std::cout, mo);
이러한 연산자를 멤버 함수로 만들 때 이러한 연산자가 직관적으로 작동하도록 할 의무가 없습니다. operator<<(int)
원하는 경우 일부 멤버 변수를 왼쪽으로 이동하도록 정의 할 수 있습니다. 얼마나 많은 댓글이 있더라도 사람들이 경계를 늦출 수 있음을 이해하십시오. 쓰다.
거의 마지막으로, 교환 원 호출에 대한 두 분해가 모두 유효한 경우가있을 수 있으며 여기에서 문제가 발생할 수 있으며 대화를 연기 할 것입니다.
마지막으로, 이항 연산자처럼 보이는 단항 멤버 연산자를 작성하는 것이 얼마나 이상 할 수 있는지 주목하십시오 (멤버 연산자를 가상으로 만들 수 있습니다 ….. 또한이 경로를 계승하지 않고 실행하려고 시도합니다 …. )
struct MyObj
{
// Note that we now return the ostream
std::ostream& operator<<(std::ostream& os) { os << *this; return os; }
int value = 8;
};
이 구문은 이제 많은 코더를 짜증나게 할 것입니다 ….
MyObj mo;
mo << std::cout << "Words words words";
// this decomposes to...
mo.operator<<(std::cout) << "Words words words";
// ... or even further ...
operator<<(mo.operator<<(std::cout), "Words words words");
cout
여기 체인에서 두 번째 인수가 어떻게되는지 주목 하십시오 …. 이상하지 않습니까?