web-dev-qa-db-ja.com

ドット、矢印、または二重コロンを使用してC ++のクラスのメンバーを参照するのはいつですか?

他のC派生言語(JavaやC#など)からC++に移行すると、C++がクラスのメンバーを参照する3つの方法を持っていることが最初は非常にわかりにくいです:a::ba.b 、およびa->b。これらの演算子のどれをいつ使用しますか?

(注:これは Stack OverflowのC++ FAQ へのエントリとなることを意図しています。このフォームでFAQを提供するというアイデアを批判したい場合、それから これをすべて開始したメタへの投稿 がそれを行う場所になります。その質問への回答は C++チャットルーム で監視され、ここでFAQアイデアはそもそも始まったので、あなたの答えはアイデアを思いついた人に読まれる可能性が非常に高いです。)

235
sbi

C++がクラスまたはクラスオブジェクトのメンバーにアクセスするために使用する3つの異なる演算子、つまり二重コロン::、ドット.、および矢印->は、3つの異なるシナリオで使用されます常に明確に定義されています。これを知ることで、どのコードでも、それぞれa::ba.b、またはa->bを見るだけで、abについてすぐに多くを知ることができます。あなたが見ます。

  1. a::bは、bがクラス(または名前空間)aのメンバーである場合にのみ使用されます。つまり、この場合、aは常にクラス(または名前空間)の名前になります。

  2. a.bは、bがオブジェクト(またはオブジェクトへの参照)aのメンバーである場合にのみ使用されます。したがって、a.bの場合、aは常にクラスの実際のオブジェクト(またはオブジェクトへの参照)になります。

  3. a->bは元々、(*a).bの略記法です。ただし、オーバーロードできるメンバーアクセス演算子は->のみであるため、aoperator->をオーバーロードするクラスのオブジェクトである場合(このような一般的な型はスマートポインターおよび反復子です) 、その意味はクラスデザイナーが実装したものです。結論:a->bでは、aがポインターである場合、bはポインターaが参照するオブジェクトのメンバーになります。ただし、aがこの演算子をオーバーロードするクラスのオブジェクトである場合、オーバーロードされた演算子関数operator->()が呼び出されます。


小さな活字:

  • C++では、classstruct、またはunionとして宣言された型は、「クラス型」と見なされます。したがって、上記は3つすべてを指します。
  • 参照は、意味的にはオブジェクトへのエイリアスなので、#3にも「またはポインターへの参照」を追加する必要がありました。しかし、ポインターへの参照(T*&)はめったに使用されません。
  • ドット演算子と矢印演算子は、オブジェクトのメンバーではない場合でも、オブジェクトの静的クラスメンバーを参照するために使用できます(これを指摘してくれたOliに感謝!
236
sbi

Sbiのポイント3の代替案を提案する

a->bは、aがポインターの場合にのみ使用されます。これは、(*a).bbが指すオブジェクトのaメンバーの省略形です。 C++には、「通常の」ポインターとスマートポインターの2種類のポインターがあります。 A* aなどの通常のポインターの場合、コンパイラは->を実装します。 std::shared_ptr<A> aなどのスマートポインターの場合、->shared_ptrクラスのメンバー関数です。

理由:このFAQの対象読者はスマートポインターを書いていません。 ->が実際にoperator->()と呼ばれること、またはオーバーロードできる唯一のメンバーアクセスメソッドであることを知る必要はありません。

36
MSalters
#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によって作成された)へのポインターからメンバー(属性および関数)にアクセスする
*ダブルコロン(::)を使用して、オブジェクトをハンドルとして使用せずに、クラス自体から静的メンバー関数にアクセスします。 [注:推奨されない.または->を使用して、インスタンスから静的メンバー関数を呼び出すこともできます]

0
Hu Xixi