C ++의 화살표 연산자가 *.의 별칭이 아닌 이유는 무엇입니까?


18

c ++에서는 반복자와 같이 * 연산자가 오버로드 될 수 있지만 화살표 (->) (. *) 연산자는 * 연산자를 오버로드하는 클래스에서는 작동하지 않습니다. 전처리 기가->의 모든 인스턴스를 (* left) .right로 쉽게 바꿀 수 있다고 생각하면 반복자를 구현하는 것이 더 좋을 것입니다. 실제와 다른 이유가 있습니까? 아니면 언어 / 디자이너 만의 특성입니까?

답변:


16

foo->bar동등한 규칙 (*foo).bar은 내장 연산자에만 적용됩니다.

단항 operator *에 포인터 역 참조 시맨틱이 항상있는 것은 아닙니다. 매트릭스 전치, 0 개 이상의 파서 일치 또는 거의 모든 것을 의미하는 라이브러리를 만들 수 있습니다.

단항에 과부하가 걸리는 operator *것이 operator ->의미가없는 의미론으로 요청하지 않은 것을 갑자기 얻는 다면 언어가 더 귀찮게 될 것입니다 .

operator -> 별도의 과부하가 가능하므로 원하는 경우 최소한의 노력으로 과부하를 걸 수 있습니다.

또한 이러한 과부하 operator ->에는 체인 중 하나가 원시 포인터를 반환 할 때까지 호출을 자동으로 연결하는 것과 같이 다소 흥미로운 속성이 있습니다 . 이는 스마트 포인터 및 기타 프록시 유형에 매우 유용합니다.

#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <string>
#include <iostream>
#include <ostream>

struct Foo
{
    boost::shared_ptr<std::string> operator -> () const
    {
        return boost::make_shared<std::string>("trololo");
    }
};

int main()
{
    Foo foo;
    std::cerr << foo->size() << std::endl;
}

당신의 모범은 무엇을 설명합니까? 문자열에 대한 스마트 포인터를 반환하고 어떻게 든 크기를 출력하고 있습니까? 혼란 스러워요.
Trevor Hickey

2
그것은 내 대답의 마지막 단락, ->무언가에 대한 원시 포인터를 얻을 때까지 연산자 체인을 사용하여 그 멤버를 역 참조하고 액세스하는 방법을 보여줍니다. operator->가 연결되지 않으면 shared_ptr이 원시 포인터가 아니기 때문에 예제가 잘못 구성됩니다.
Lars Viklund

@LarsViklund : 귀하의 답변에 문제가 있습니다 : "연산자-> ... 연산자 중 하나가 원시 포인터를 반환 할 때까지 자동으로 운영자-> 체인을 연결합니다"라고 말했습니다. A->B최대 1 번의 추가 호출에서 구문 체인을 사용하는 것은 올바르지 않습니다 . C ++-> 이진 구문이 실제로하는 것은 객체를 opeartor->직접 호출하는 것이 아니라 유형을보고 A원시 포인터인지 확인하는 것입니다. 만약 그것을 ->거부하고 실행 B하면, 그렇지 않으면 객체를 호출하고 operator->, 결과를 거부합니다 (기본 원시 포인터 또는 다른 것을 사용 하여 결과에 operator->실행)B
Guss

@Guss : 귀하의 주장에 대한 장과 구절을 찾을 수 없으며 컴파일러에서 재현 할 수 없습니다. C ++ 11 13.5.6 / 1은 적합한 과부하가 존재하는 경우 x->m로 해석 됨을 나타냅니다 (x.operator->())->m. LHS가 operator->다시 과부하가 적절한 경우이 프로세스는 일반적인 (*x).m효과가 5.2.5 / 2가 될 때까지 반복 됩니다.
Lars Viklund

8

"C ++ 프로그래밍 언어"는 이러한 연산자가 서로 다르기 때문에 다음과 같이 말합니다.

당신이 더 많은 이러한 연산자 중 하나 이상 제공하는 경우, 그것은을 확인하는 것이 현명하다 것처럼, 등가를 제공하는 것이 현명 수 있습니다 ++xx+=1같은 효과를 가지고 x=x+1간단한 변수에 대한 x몇 가지 클래스를 경우 ++, + =, =, 및 +가 제공됩니다.

따라서 언어 디자이너는 항상 동일한 것을 원한다고 가정하지 않고 서로 다른 과부하 지점을 원할 수 있으므로 별도의 과부하 지점을 제공 한 것 같습니다 .


7

의 과부하 때문에 일반적으로 C ++는 찬성의 유연성으로 설계 *하고 ->별도입니다. 그렇게하는 것은 매우 드문 일이지만, 충분히 과도하게 원한다면 완전히 다른 일을하기 위해 과부하를 작성할 수 있습니다 (예 : C ++ 내부에서 구현 된 도메인 특정 언어에 적합 할 수 있음).

즉, 반복자 두 가지 사용법을 모두 지원합니다. 고대 구현에서는. (*iter).whatever대신 필요한 라이브러리를 찾을 수 iter->whatever있지만, 그렇다면 언어의 특성이 아닌 구현의 버그입니다. 모든 표준 컨테이너 / 알고리즘 / 반복기를 구현하는 데 필요한 작업량을 감안할 때 일부 초기 릴리스가 다소 불완전한 것은 놀라운 일이 아니지만 실제로 그런 식으로 의도 된 것은 아닙니다.


표준 라이브러리 컨테이너가 구현되어 있음을 깨닫지 못했거나 과부하가 가능했습니다.
Jakob Weisblat

3
C ++ 03 24.1 / 1 (*i).m은 유효한 반복자 가 i->m동일한 의미로 지원해야합니다 .
Lars Viklund
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.