나는, 멤버 액세스 연산자를 제외한 대부분의 연산자 오버로딩을 이해 ->
, .*
, ->*
등
특히,이 연산자 함수로 전달되는 것은 무엇이고 무엇을 반환해야합니까?
운영자 기능 (예 operator->(...)
:)은 어떤 멤버가 참조되고 있는지 어떻게 알 수 있습니까? 알 수 있습니까? 심지어 알아야합니까?
마지막으로 고려해야 할 const 고려 사항이 있습니까? 예를 들어과 같은 것을 오버로드 할 때는 operator[]
일반적으로 const 버전과 non-const 버전이 모두 필요합니다. 멤버 액세스 연산자에는 const 및 non-const 버전이 필요합니까?
답변
->
이것은 정말 까다로운 유일한 것입니다. 비 정적 멤버 함수 여야하며 인수를 사용하지 않습니다. 반환 값은 멤버 조회를 수행하는 데 사용됩니다.
리턴 값이 포인터가 아닌 클래스 유형의 다른 오브젝트 인 경우 후속 멤버 검색도 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"
}
->*
이것은 특별한 것이 없다는 점에서 까다 롭습니다. 비 오버로드 버전은 클래스 왼쪽에 유형과 오른쪽에 멤버 유형 포인터의 객체에 대한 포인터의 객체를 필요로한다. 그러나 과부하가 걸리면 원하는 인수를 취하고 원하는 것을 반환 할 수 있습니다. 비 정적 멤버 일 필요도 없습니다.
즉, 이와 같은 단지 일반적인 이진 연산자 +
, -
및 /
. 참조 : 무료 연산자-> * 과부하가 악한가?
.*
과 .
오버로드 할 수 없습니다. 왼쪽이 클래스 유형일 때 이미 내장 된 의미가 있습니다. 어쩌면 왼쪽에 포인터로 정의 할 수있는 것이 다소 합리적이지만 언어 설계위원회는 유용하다고 생각하는 것이 더 혼란 스럽다고 결정했습니다.
오버로드 ->
, ->*
, .
, 및 .*
표현이 정의되지 않은 될 경우에만 경우에 입력 할 수 있습니다, 그것은 전혀 오버로드로 유효한 것입니다 표현의 의미를 변경하지 않을 수 있습니다.
답변
연산자->는 특별합니다.
“비정형적인 추가 제약이 있습니다. 포인터 역 참조 연산자가있는 객체 (또는 객체에 대한 참조)를 반환하거나 포인터 역 참조 연산자 화살표가 가리키는 항목을 선택하는 데 사용할 수있는 포인터를 반환해야합니다. ”
Bruce Eckel : Thinking CPP Vol-one : 운영자->
편의를 위해 추가 기능이 제공되므로 전화하지 않아도됩니다.
a->->func();
간단하게 할 수 있습니다 :
a->func();
따라서 연산자->가 다른 연산자 과부하와 다릅니다.
답변
멤버 액세스를 오버로드 할 수 없습니다 .
(예 : 두 번째 부분 ->
). 그러나 단항 역 참조 연산자 *
(즉, 작업의 첫 번째 부분)에 과부하를 걸 수 있습니다 ->
.
는 C ++ ->
연산자는 기본적으로 두 단계의 결합이며, 당신이 생각하면이 분명하다 x->y
동일합니다 (*x).y
. C ++을 사용하면 클래스의 인스턴스 일 (*x)
때 파트 로 수행 할 작업을 사용자 정의 할 수 있습니다 x
.
->
오버로드 의 시맨틱 은 다소 이상하다. C ++에서는 (포인팅 된 객체를 찾는 데 사용될) 일반 포인터를 반환하거나이 클래스가 ->
연산자를 제공하는 경우 다른 클래스의 인스턴스를 반환 할 수 있기 때문에 다소 이상하다 . 이 두 번째 경우에는 참조 해제 된 객체에 대한 검색이이 새 인스턴스에서 계속됩니다.
답변
->
지적되는 내용 회원 모르는 연산자, 그것은 단지의 실제 멤버 액세스를 수행하는 객체를 제공합니다.
또한 const 및 non-const 버전을 제공 할 수없는 이유가 없습니다.
답변
연산자-> () (여기에 인수가 전달되지 않음)를 오버로드 할 때 컴파일러가 실제로하는 일은 유형에 대한 실제 포인터를 반환 할 때까지 재귀 적으로 호출하는 것입니다. 그런 다음 올바른 멤버 / 방법을 사용합니다.
예를 들어 실제 포인터를 캡슐화하는 스마트 포인터 클래스를 만드는 데 유용합니다. 오버로드 된 operator->가 호출되고 수행하는 모든 작업 (예 : 스레드 안전을위한 잠금)이 수행되고 내부 포인터를 반환 한 다음 컴파일러가이 내부 포인터에 대해->를 호출합니다.
constness에 관해서는-의견과 다른 답변에 답변되었습니다 (둘 다 제공 할 수 있고 제공해야합니다).