C ++에서 클래스 멤버를 가리키는 점, 화살표 또는 이중 콜론을 언제 사용합니까?


243

: C로 (Java 또는 C #을 같은) 다른 C 파생 언어에서 오는 ++, 먼저 매우 C ++ 세 가지 클래스의 멤버를 참조 할 수있는 방법이 있는지 혼란에있다 a::b, a.b등을 a->b. 이 연산자 중 어느 것을 언제 사용합니까?

(참고 : 이것은 Stack Overflow의 C ++ FAQ에 대한 항목 입니다.이 양식으로 FAQ를 제공한다는 아이디어를 비판하려면이 모든 것을 시작한 메타에 게시 하면됩니다. 이 질문은 C ++ 대화방 에서 모니터링되며 여기서 FAQ 아이디어는 처음부터 시작되었으므로 아이디어를 얻은 사람들이 귀하의 답변을 읽을 가능성이 큽니다.)

답변:


248

C ++가 클래스 또는 클래스 객체의 멤버에 액세스하기 위해 사용하는 세 개의 고유 연산자, 즉 double colon ::, dot .및 arrow ->은 항상 잘 정의 된 세 가지 시나리오에 사용됩니다. 이것을 아는 것은 즉시에 대해 꽤 많이 알 수 있습니다 ab단지보고에 의해 a::b, a.b또는 a->b당신이 볼 코드의 각각을,.

  1. a::bb클래스 (또는 네임 스페이스)의 멤버 인 경우에만 사용됩니다 a. 즉,이 경우 a항상 클래스 이름 (또는 네임 스페이스)이됩니다.

  2. a.bb객체 (또는 객체 참조)의 멤버 인 경우에만 사용됩니다 a. 에 대한 그래서 a.b, a항상 클래스의 실제 객체 (또는 객체에 대한 참조)입니다.

  3. a->b원래의 약칭 표기법입니다 (*a).b. 그러나 ->오버로드 할 수있는 유일한 멤버 액세스 연산자이므로 오버로드 a되는 클래스의 오브젝트 operator->(일반적인 이러한 유형은 스마트 포인터 및 반복자) 인 경우 클래스 디자이너가 구현 한 의미입니다. 결론 :와이 a->b경우, a포인터입니다, b포인터가 개체의 구성원이 될 것 a을 의미한다. 그러나이 a연산자를 오버로드하는 클래스의 객체 인 경우 오버로드 된 연산자 함수 operator->()가 호출됩니다.


작은 글씨 :

  • C ++에서 유형으로 선언 class, struct또는 union"클래스 타입"으로 간주됩니다. 위의 세 가지를 모두 참조하십시오.
  • 참조는 의미 상으로 객체에 대한 별칭이므로 # 3에 "또는 포인터에 대한 참조"도 추가해야합니다. 그러나 포인터 ( T*&) 에 대한 참조 가 거의 사용되지 않기 때문에 이것이 도움이되는 것보다 더 혼란 스러울 것이라고 생각했습니다 .
  • 점 및 화살표 연산자는 객체의 멤버가 아니더라도 객체의 정적 클래스 멤버를 참조하는 데 사용할 수 있습니다. (Oli에게 이것을 지적 해 주셔서 감사합니다!)

10
가능성이 있음을 명확히해야 .하고 ->그들이 "개체의 멤버"엄격하지 않은 경우에도, 또한 객체를 통해 액세스 클래스의 정적에 사용할 수있다.
Oliver Charlesworth

@Oli : 사실입니다. 본문에 기재하기에는 흔하고 중요하지 않다고 생각하기 때문에 작은 글씨에 추가했습니다.
sbi

3
완전성 operator*()을 위해 오버로드 될 수 있으며 과부하가 발생하는 것을 강제하지 않는 것이 좋습니다 operator->()! (저는 BTW를
공감

@OliCharlesworth C ++ 표준에서 어디에 지정되어 있는지 알고 싶습니까?
돼지

1
@juanchopanza : 그러나 ->과부하 operator*를 사용하여 체인 동작을 얻을 수는 없습니다 .. operator->과부하 만 이 그것을 얻습니다.
벤 Voigt

36

SBI의 요점 3에 대한 대안 제안

a->ba포인터 인 경우에만 사용됩니다 . 가리키는 객체 (*a).bb멤버 인 속기입니다 a. C ++에는 "일반"및 스마트 포인터라는 두 가지 종류의 포인터가 있습니다. 와 같은 일반 포인터의 A* a경우 컴파일러가 구현 ->합니다. 예컨대 스마트 포인터를 들어 std::shared_ptr<A> a, ->클래스의 멤버 함수이다 shared_ptr.

근거 :이 FAQ의 대상은 스마트 포인터를 작성하지 않습니다. 그들은 ->실제로라는 것을 알 필요가 operator->()없거나 과부하 될 수있는 유일한 멤버 액세스 방법이라는 것을 알 수 있습니다.


4
동의 여부에 관계없이 +1대체 답변을 제공하기위한 것입니다.
sbi

2
글쎄, 공정 ->하게도 C ++ 프로그래머가 곧 만나야 할 표준 반복자에 과부하가 걸리므로 포인터에만 사용된다는 말은 혼란 스러울 수 있습니다.
Kiscsirke

@Kiscsirke "일반적인 C ++ 프로그래머"는 스마트 포인터 나 이터레이터 유형을 작성할 필요가 없으며 그냥 사용합니다. "포인터와 같은 참조"는 둘 다에 적용됩니다.
Caleth

0
#include <iostream>
#include <string>

using namespace std;

class Human {
private:
    int age;

public:
    string name;

    Human(int humanAge, string humanName) 
         : age(humanAge), name(std::move(humanName)) {}

    void DoSomething() {
        cout << age << endl;
    }

    static void DisplayAge(const Human& person) {
        cout << person.age << endl;
    }

    // ...
};

int main() {
    // Usage of Dot(.) 
    Human firstMan(13, "Jim"); // firstMan is an instance of class Human
    cout << firstMan.name << endl; // accessing member attributes
    firstMan.DoSomething(); // accessing member functions

    // Usage of Pointer Operator (->)
    Human* secondMan = new Human(24, "Tom");
    cout << secondMan->name << endl; // accessing member attributes
    secondMan->DoSomething(); // accessing member functions
    cout << (*secondMan).name << endl; // accessing member attributes
    (*secondMan).DoSomething(); // accessing member functions

    // Usage of Double Colon (::)
    Human::DisplayAge(firstMan);
    firstMan.DisplayAge(firstMan); // ok but not recommended
    secondMan->DisplayAge(firstMan); // ok but not recommended

    delete(secondMan);

    return 0;
}

상기 부호화 예에서, 우리는 참조한다 :
* 점 연산자 (사용하여 인스턴스 (또는 물체)으로부터 부재 (특성 및 기능)에 액세스 .)
오브젝트 포인터로부터 부재 (특성 및 기능)에 액세스 *을 (또는 의해 생성 new) 포인터 연산자 사용 ( ->)
* 이중 콜론 ( ::)을 사용하여 객체를 핸들로 사용하지 않고 클래스 자체에서 정적 멤버 함수에 액세스 [ 참고 :. 또는 ->권장하지 않는 인스턴스에서 정적 멤버 함수를 호출 할 수도 있습니다 . ]


@ sbi 너무 심술 쟁이, 나는 그것이 일종의 반복이라는 것을 안다. 나는 그것들을 사용하는 방법을 보여주는 명확한 예를주고 싶다. 그리고 내가 말한 곳 ->은 힙에 할당 된 포인터 만 사용할 수 new있습니까? 아래에서 두 번째 항목 ->은 포인터 용 임을 분명히 나타 냅니다. 그리고 downvote하기 전에 className::non_static_member_function()c ++ 14를 직접 사용해 보는 것이 좋습니다 . 참조는 포인터가 아니므로 사용할 수 있으며 .대답에서 더 명확하게 설명합니다.
Hu Xixi

0

도트 연산자는 직접 멤버 선택 시나리오 에서 사용됩니다 .

print(a.b)

여기서는 b객체의 직접 멤버 인에 액세스 하고 a있습니다. 따라서 주로 a객체이며 b의 멤버 (함수 / 변수 등)입니다 a.


화살표 연산자는 간접 멤버 선택 시나리오 에서 사용됩니다 .

print(a->b)

여기서는 b객체의 멤버 인에 액세스 하고 a있습니다. (*a).b여기서는 축약 형 이므로 a주로 객체에 대한 포인터 b이며 해당 객체의 멤버입니다.


이중 콜론 (Scope) 연산자는 네임 스페이스 관련 직접 멤버 선택 시나리오에서 사용됩니다.

print(a::b)

여기서 우리는 bclass / namespace의 멤버 인 어느 것에 액세스 하고 있습니다. a따라서 주로 a클래스 / 네임 스페이스이며 b의 멤버 (함수 / 변수 등)입니다 a.

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