멤버 함수로 선언 된 오버로드 된 연산자는 하나의 매개 변수 만 가질 수 있고 자동으로 전달되는 다른 매개 변수는 포인터 이기 때문에 비대칭 이라는 것을 읽었습니다 this
. 따라서 이들을 비교할 기준이 없습니다. 반면 a friend
로 선언 된 오버로드 된 연산자는 동일한 유형의 두 인수를 전달하므로 비교할 수 있기 때문에 대칭 입니다.
내 질문은 포인터의 lvalue를 참조와 비교할 수 있는데 왜 친구가 선호됩니까? (비대칭 버전을 사용하면 대칭과 동일한 결과가 나타납니다.) STL 알고리즘이 대칭 버전 만 사용하는 이유는 무엇입니까?
답변
연산자 오버로드 된 함수를 멤버 함수로 정의하면 컴파일러는 식 s1 + s2
을 s1.operator+(s2)
. 즉, 연산자 오버로드 된 멤버 함수가 첫 번째 피연산자에서 호출됩니다. 이것이 멤버 함수가 작동하는 방식입니다!
그러나 첫 번째 피연산자가 클래스가 아니면 어떻게 될까요? 첫 번째 피연산자가 클래스 유형이 아닌 연산자를 오버로드하려는 경우 큰 문제가 double
있습니다. 그래서 당신은 이렇게 쓸 수 없습니다 10.0 + s2
. 그러나 같은 식에 대해 연산자 오버로드 멤버 함수를 작성할 수 있습니다 s1 + 10.0
.
이 순서 문제 를 해결하기 위해 멤버 friend
에 액세스해야하는 경우 연산자 오버로드 함수를 정의 private
합니다. 비공개 회원에 액세스해야 할 friend
때만 만드십시오 . 그렇지 않으면 단순히 캡슐화 를 향상시키기 위해 친구가 아닌 비회원 함수로 만드십시오 !
class Sample
{
public:
Sample operator + (const Sample& op2); //works with s1 + s2
Sample operator + (double op2); //works with s1 + 10.0
//Make it `friend` only when it needs to access private members.
//Otherwise simply make it **non-friend non-member** function.
friend Sample operator + (double op1, const Sample& op2); //works with 10.0 + s2
}
읽어보기 :
피연산자 순서의 약간의 문제
비 멤버 함수가 캡슐화를 개선하는 방법
답변
전역 연산자 오버로드와 멤버 함수 연산자 오버로드 friend
사이이기 때문에 연산자 오버로드와 멤버 함수 연산자 오버로드를 반드시 구분할 필요는 없습니다 .
전역 연산자 오버로드 를 선호하는 한 가지 이유 는 이항 연산자 의 오른쪽 에 클래스 유형이 나타나는 식을 허용하려는 경우 입니다. 예를 들면 :
Foo f = 100;
int x = 10;
cout << x + f;
이것은 전역 연산자 오버로드가있는 경우에만 작동합니다.
Foo 연산자 + (int x, const Foo & f);
전역 연산자 오버로드가 반드시 friend
함수일 필요는 없습니다 . 의 비공개 멤버에 대한 액세스가 필요한 경우에만 필요 Foo
하지만 항상 그런 것은 아닙니다.
관계없이 Foo
다음과 같이 멤버 함수 연산자 오버로드 만있는 경우 :
class Foo
{
...
Foo operator + (int x);
...
};
… 그러면 더하기 연산자 Foo
의 왼쪽 에 인스턴스가 나타나는 표현식 만 가질 수 있습니다 .