연산자 오버로딩 : 멤버 함수 대 비 멤버 함수?


121

멤버 함수로 선언 된 오버로드 된 연산자는 하나의 매개 변수 만 가질 수 있고 자동으로 전달되는 다른 매개 변수는 포인터 이기 때문에 비대칭 이라는 것을 읽었습니다 this. 따라서 이들을 비교할 기준이 없습니다. 반면 a friend로 선언 된 오버로드 된 연산자는 동일한 유형의 두 인수를 전달하므로 비교할 수 있기 때문에 대칭 입니다.

내 질문은 포인터의 lvalue를 참조와 비교할 수 있는데 왜 친구가 선호됩니까? (비대칭 버전을 사용하면 대칭과 동일한 결과가 나타납니다.) STL 알고리즘이 대칭 버전 만 사용하는 이유는 무엇입니까?


11
귀하의 질문은 실제로 이항 연산자에 관한 것입니다. 오버로드 된 모든 연산자가 단일 매개 변수로 제한되는 것은 아닙니다. () 연산자는 여러 매개 변수를 사용할 수 있습니다. 반면 단항 연산자는 매개 변수를 가질 수 없습니다.
Charles Salvia 2011 년


4
이것은에서 다루는 많은 주제 중 하나입니다 C ++ FAQ : 연산자 오버로딩
벤 보이트

답변:


148

연산자 오버로드 된 함수를 멤버 함수로 정의하면 컴파일러는 식 s1 + s2s1.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
}

읽어보기 :
피연산자 순서의 약간의 문제
비 멤버 함수가 캡슐화를 개선하는 방법


2
"그것을 확인 friend이 액세스 개인 members..and에 필요로하는 경우에만 당신이 해달라고하면 / 우, 쓰기 접근 지루하다?
badmaash

4
@Abhi : 선택 선택 : 향상된 캡슐화 vs 게으른 쓰기 습관!
Nawaz 2011 년

6
@matthias, 모든 연산자가 교환 가능한 것은 아닙니다. 간단한 예는 a/b.
EDA-QA-모트 ORA-Y

3
비 멤버 운영자가 요구하는 것을 피하는 일반적인 방법 friend은 오퍼레이션 할당 오퍼레이터 (거의 확실하게 공개 멤버가 될 것임) 측면에서 구현하는 것입니다. 예를 들어 T T::operator+=(const T &rhs)멤버로 정의한 다음 비 멤버 T operator(T lhs, const T &rhs)return lhs += rhs;. 비 멤버 함수는 클래스와 동일한 네임 스페이스에 정의되어야합니다.
Adrian McCarthy

2
@ricky :하지만 lhs가 복사본이면 (내 의견에있는 것처럼) lhs가 변경된다는 사실은 중요하지 않습니다.
Adrian McCarthy

20

전역 연산자 오버로드와 멤버 함수 연산자 오버로드 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왼쪽 에 인스턴스가 나타나는 표현식 만 가질 수 있습니다 .


3
+1은 회원 기능과 친구 기능이 아닌 회원 기능과 비회원 기능을 구분합니다. 오늘은 "글로벌 또는 네임 스페이스 범위"라고 말할 것 같습니다.
Adrian McCarthy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.