멤버 액세스 연산자 과부하->,. *


129

나는, 멤버 액세스 연산자를 제외한 대부분의 연산자 오버로딩을 이해 ->, .*, ->*

특히,이 연산자 함수로 전달되는 것은 무엇이고 무엇을 반환해야합니까?

운영자 기능 (예 operator->(...):)은 어떤 멤버가 참조되고 있는지 어떻게 알 수 있습니까? 알 수 있습니까? 심지어 알아야합니까?

마지막으로 고려해야 할 const 고려 사항이 있습니까? 예를 들어과 같은 것을 오버로드 할 때는 operator[]일반적으로 const 버전과 non-const 버전이 모두 필요합니다. 멤버 액세스 연산자에는 const 및 non-const 버전이 필요합니까?


1
나는 위의 C ++-Faq이 위의 Q에서 질문 한 모든 Q를 건드리고 있다고 생각합니다.
Alok Save

constconst버전의 버전은 필요operator-> 하지 않지만 둘 다 제공하면 유용 할 수 있습니다.
Fred Foo


9
@Als : FAQ에는 ->*및 오버로드 방법이 설명되어 있지 않습니다 .*. 사실, 그것들은 언급조차하지 않습니다! 나는 그들이 FAQ에 드물게 있다고 생각하지만,이 질문을 FAQ에서 기꺼이 연결합니다. FAQ의 속임수로 이것을 닫지 마십시오!
sbi

@ sbi, 나는 당신의 (굉장한) FAQ 에서이 질문에 대한 링크를 찾지 못했습니다. 그리고 중복 질문을했습니다. 더 분명하게 만들 수 있습니까? (이미 분명한 경우 사과).
P i

답변:


144

->

이것은 정말 까다로운 유일한 것입니다. 비 정적 멤버 함수 여야하며 인수를 사용하지 않습니다. 반환 값은 멤버 조회를 수행하는 데 사용됩니다.

리턴 값이 포인터가 아닌 클래스 유형의 다른 오브젝트 인 경우 후속 멤버 검색도 operator->함수에 의해 처리됩니다 . 이것을 "드릴 다운 동작"이라고합니다. 언어 operator->는 마지막 호출이 포인터를 반환 할 때까지 호출을 연결합니다 .

struct client
    { int a; };

struct proxy {
    client *target;
    client *operator->() const
        { return target; }
};

struct proxy2 {
    proxy *target;
    proxy &operator->() const
        { return * target; }
};

void f() {
    client x = { 3 };
    proxy y = { & x };
    proxy2 z = { & y };

    std::cout << x.a << y->a << z->a; // print "333"
}

->*

이것은 특별한 것이 없다는 점에서 까다 롭습니다. 비 오버로드 버전은 클래스 왼쪽에 유형과 오른쪽에 멤버 유형 포인터의 객체에 대한 포인터의 객체를 필요로한다. 그러나 과부하가 걸리면 원하는 인수를 취하고 원하는 것을 반환 할 수 있습니다. 비 정적 멤버 일 필요도 없습니다.

즉, 이와 같은 단지 일반적인 이진 연산자 +, -/. 참조 : 무료 연산자-> * 과부하가 악한가?

.*.

오버로드 할 수 없습니다. 왼쪽이 클래스 유형일 때 이미 내장 된 의미가 있습니다. 어쩌면 왼쪽에 포인터로 정의 할 수있는 것이 다소 합리적이지만 언어 설계위원회는 유용하다고 생각하는 것이 더 혼란 스럽다고 결정했습니다.

오버로드 ->, ->*, ., 및 .*표현이 정의되지 않은 될 경우에만 경우에 입력 할 수 있습니다, 그것은 전혀 오버로드로 유효한 것입니다 표현의 의미를 변경하지 않을 수 있습니다.


2
마지막 진술은 완전히 사실이 아닙니다. 예를 들어, 오버로드 new되지 않은 경우에도 연산자 가 오버로드 되어도 오버로드 할 수 있습니다 .
Matt

6
@Matt new는 항상 오버로드되거나 오버로드 규칙이 실제로 적용되지 않습니다 (13.5 / 5 : 할당 및 할당 취소 기능, operator new, operator new [], operator delete 및 operator delete []은 3.7에 완전히 설명되어 있습니다. 0.4.이 절의 나머지 부분에서 발견 된 속성 및 제한. 명시 적으로 3.7.4에 명시하지 않는 한 그들에게 적용)하지만 단항 과부하하지 않습니다 &또는 이진 &&, ||, 또는 ,, 또는의 과부하를 추가 operator=하거나, 범위가 지정되지 않은 아무것도에 대해 단지 과부하 열거 형은 표현식의 의미를 변경할 수 있습니다. 성명을 명확하게했습니다. 감사합니다!
Potatoswatter

41

연산자->는 특별합니다.

"비정형적인 추가 제약이 있습니다. 포인터 역 참조 연산자가있는 객체 (또는 객체에 대한 참조)를 반환하거나 포인터 역 참조 연산자 화살표가 가리키는 항목을 선택하는 데 사용할 수있는 포인터를 반환해야합니다. " Bruce Eckel : Thinking CPP Vol-one : 운영자->

편의를 위해 추가 기능이 제공되므로 전화하지 않아도됩니다.

a->->func();

간단하게 할 수 있습니다 :

a->func();

따라서 연산자->가 다른 연산자 과부하와 다릅니다.


3
이 답변은 더 많은 크레딧이 필요하며 해당 링크에서 Eckel의 책을 다운로드 할 수 있으며 정보는 1 권 12 장에 있습니다.
P i

26

멤버 액세스를 오버로드 할 수 없습니다 .(예 : 두 번째 부분 ->). 그러나 단항 역 참조 연산자 *(즉, 작업의 첫 번째 부분)에 과부하를 걸 수 있습니다 ->.

는 C ++ ->연산자는 기본적으로 두 단계의 결합이며, 당신이 생각하면이 분명하다 x->y동일합니다 (*x).y. C ++을 사용하면 클래스의 인스턴스 일 (*x)때 파트 로 수행 할 작업을 사용자 정의 할 수 있습니다 x.

->오버로드 의 시맨틱 은 다소 이상하다. C ++에서는 (포인팅 된 객체를 찾는 데 사용될) 일반 포인터를 반환하거나이 클래스가 ->연산자를 제공하는 경우 다른 클래스의 인스턴스를 반환 할 수 있기 때문에 다소 이상하다 . 이 두 번째 경우에는 참조 해제 된 객체에 대한 검색이이 새 인스턴스에서 계속됩니다.


2
좋은 설명! ->*그것은의 형태와 동일하기 때문에에 대해 동일한 것을 의미한다고 생각 (*x).*합니까?
빙고

10

->지적되는 내용 회원 모르는 연산자, 그것은 단지의 실제 멤버 액세스를 수행하는 객체를 제공합니다.

또한 const 및 non-const 버전을 제공 할 수없는 이유가 없습니다.


7

연산자-> () (여기에 인수가 전달되지 않음)를 오버로드 할 때 컴파일러가 실제로하는 일은 유형에 대한 실제 포인터를 반환 할 때까지 재귀 적으로 호출하는 것입니다. 그런 다음 올바른 멤버 / 방법을 사용합니다.

예를 들어 실제 포인터를 캡슐화하는 스마트 포인터 클래스를 만드는 데 유용합니다. 오버로드 된 operator->가 호출되고 수행하는 모든 작업 (예 : 스레드 안전을위한 잠금)이 수행되고 내부 포인터를 반환 한 다음 컴파일러가이 내부 포인터에 대해->를 호출합니다.

constness에 관해서는-의견과 다른 답변에 답변되었습니다 (둘 다 제공 할 수 있고 제공해야합니다).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.