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


243

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

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

回答:


248

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

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

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

  3. a->bは、もともとはの省略表記です(*a).b。ただし、->はオーバーロードできる唯一のメンバーアクセス演算子です。したがって、aがオーバーロードするクラスのオブジェクトである場合operator->(一般的なタイプはスマートポインターとイテレーターです)、意味はクラスデザイナーが実装したものです。結論:を使用a->bするaと、がポインターbの場合、ポインターがa参照するオブジェクトのメンバーになります。ただし、aこの演算子をオーバーロードするクラスのオブジェクトである場合、オーバーロードされた演算子関数operator->()が呼び出されます。


小さな文字:

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

10
おそらくことを明らかにしなければならない.->、彼らは「オブジェクトのメンバー」厳密でなくてもかかわらず、また、オブジェクトを介してアクセスクラスの静的に使用することができます。
Oliver Charlesworth

@オリ:確かにそうです。メインテキストに掲載するのは一般的ではなく、重要でもないので、細かい部分に追加しました。
sbi

3
完全を期すために、これoperator*()もオーバーロードされる可能性があり、そのオーバーロードがoperator->()!(私はBTWに反対票を投じなかった、重複の長いシーケンスを介してここに
たどり着いた

@OliCharlesworthは、それがC ++標準のどこに指定されているか知っていますか?

1
@juanchopanza:ただし、を->オーバーロードoperator*して使用しても.、の連鎖動作を取得することはできません。operator->オーバーロードのみがそれを取得します。
Ben Voigt 2014

36

sbiのポイント3の代替案を提案

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

理論的根拠:このFAQの対象読者はスマートポインターを作成していません。彼らは、->が実際に呼び出されoperator->()ていること、またはそれがオーバーロードできる唯一のメンバーアクセスメソッドであることを知る必要はありません。


4
私がそれに同意するかどうかに関係なく、私はこれを+1代替の答えを提供するためだけに与えます。
sbi

2
まあ、公平に->言うと、C ++プログラマーがすぐに会う必要のある標準のイテレータもオーバーロードされるので、ポインタにのみ使用されると言うと混乱を招く可能性があります。
Kiscsirke 2013年

@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か?以下、2番目の項目ですが、これ->はポインタ用であることを明確に示しています。反対票を投じる前にclassName::non_static_member_function()、自分でc ++ 14を試してみてください。参照はポインタではないため、を使用できます.。私の回答でそれをより明確にします。
Hu

0

ドット演算子は、直接メンバー選択シナリオで使用されます。

print(a.b)

ここではb、オブジェクトの直接メンバーであるにアクセスしていますa。したがって、主にaはオブジェクトでbあり、のメンバー(関数/変数など)ですa


矢印演算子は、間接的なメンバー選択シナリオで使用されます。

print(a->b)

ここbでは、が指すオブジェクトのメンバーであるにアクセスしていaます。これは(*a).b、ここでaは主にオブジェクトへのポインタでbあり、そのオブジェクトのメンバーです。


二重コロン(スコープ)演算子は、名前空間関連の直接メンバー選択シナリオで使用されます。

print(a::b)

ここではb、クラス/名前空間のメンバーであるにアクセスしています。aしたがって、主にa、クラス/名前空間でbあり、のメンバー(関数/変数など)ですa

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.