メンバーアクセス演算子のオーバーロード->、。*


129

私は、メンバーアクセス演算子を除いて、ほとんどの演算子のオーバーロードを理解し->.*->*など

特に、これらの演算子関数に渡されるものと返されるものは何ですか?

演算子関数(例operator->(...))は、どのメンバーが参照されているかをどのようにして知るのですか?わかる?それも知る必要がありますか?

最後に、考慮に入れる必要があるconstの考慮事項はありますか?たとえば、のようなものをオーバーロードする場合operator[]、通常、constバージョンとnon-constバージョンの両方が必要になります。メンバーアクセスオペレーターにはconstバージョンとnon-constバージョンが必要ですか?


1
私はC ++を超えると信じて-よくある質問は、すべてのQさんQ:上記に尋ねた時に触れる
Alok保存

constおよびの非constバージョンは必須operator->はありません、両方を提供すると便利です。
Fred Foo


9
@Als:FAQは、オーバーロード->*および.*。実際、それらについても触れられていません!FAQに載ることはまれだと思いますが、この質問をFAQから喜んでリンクします。FAQの真似としてこれを閉じないでください!
sbi 2012年

@sbi、私はあなたの(素晴らしい)FAQからこの質問へのリンクを見つけるのに完全に失敗し、重複した質問をすることになりました。もっとはっきりさせてくれませんか?(すでに明らかな場合はお詫び)。
P i

回答:


144

->

これは本当にトリッキーな唯一のものです。これは非静的メンバー関数である必要があり、引数を取りません。戻り値は、メンバーの検索を実行するために使用されます。

戻り値がポインターではなくクラス型の別のオブジェクトである場合、その後のメンバー検索も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"
}

->*

これは特別なことは何もないという点でトリッキーです。非オーバーロードバージョンは、クラス左側のタイプ、右側にメンバー型へのポインタのオブジェクトへのポインタのオブジェクトを必要とします。しかし、オーバーロードすると、好きな引数を取り、必要なものを返すことができます。非静的メンバーである必要もありません。

換言すれば、これは、単にような通常のバイナリ演算子であり+-および/。参照:無料のoperator-> *オーバーロードは悪か?

.* そして .

これらはオーバーロードできません。左側がクラス型の場合、組み込みの意味はすでにあります。おそらく、左側のポインターに対してそれらを定義できることは少し意味があるかもしれませんが、言語設計委員会は、有用ではなく混乱を招くと判断しました。

オーバーロード->->*.およびの.*式が未定義の場合にのみ入力できなしで有効になる式の意味を変更することはできません。


2
あなたの最後の声明は完全に真実ではありません。たとえば、new演算子はオーバーロードされていなくても有効ですが、オーバーロードできます。
マット

6
@Mattはよく、new常にオーバーロードされているか、オーバーロードの規則が実際には適用されません(13.5 / 5:割り当て関数と割り当て解除関数、演算子new、演算子new []、演算子deleteおよび演算子delete []は3.7で完全に説明されています0.4。属性と制限が明示的に3.7.4で述べられない限り、それらには適用されません。この項の残りの部分で見つかった。)しかし、単項の過負荷&またはバイナリを&&||または,、またはの過負荷を加えることoperator=、またはスコープを持たないために何でもただのオーバーロード列挙型。式の意味を変更できます。声明を明確にした、ありがとう!
Potatoswatter 2013

41

演算子->は特別です。

「追加の非定型的な制約があります。ポインター逆参照演算子も持つオブジェクト(またはオブジェクトへの参照)を返すか、ポインター逆参照演算子の矢印が指しているものを選択するために使用できるポインターを返す必要があります。 」 ブルース・エッケル:Thinking CPP Vol-one:operator->

追加の機能は便宜上提供されているため、呼び出す必要はありません

a->->func();

あなたは単に行うことができます:

a->func();

これにより、演算子が他の演算子のオーバーロードと異なります。


3
この答えはもっと信用に値します、あなたはそのリンクからEckelの本をダウンロードすることができます、そして情報は第1巻の第12章にあります。
P i

26

メンバーアクセスをオーバーロードすることはできません.(つまり、機能の2番目の部分->)。ただし、単項逆参照演算子*(つまり、最初の部分->)をオーバーロードすることができます。

C ++ ->演算子は基本的に2つのステップの和集合であり、これがx->yと同等であると考えれば明らかです(*x).y。C ++では、がクラスのインスタンスである場合に、(*x)パーツの処理方法をカスタマイズできますx

->C ++では通常のポインター(ポインターが指すオブジェクトの検索に使用される)を返すことも、このクラスが->演算子も提供する場合は別のクラスのインスタンスを返すこともできるため、オーバーロードのセマンティクスは少し奇妙です。この2番目の場合、間接参照されたオブジェクトの検索は、この新しいインスタンスから続行されます。


2
素晴らしい説明!->*それはの形と同じなので、も同じことを意味すると思い(*x).*ますか?
ビンゴ

10

->指されているものメンバーを知らないオペレータは、それだけで、実際のメンバーへのアクセスを実行するためのオブジェクトを提供します。

さらに、constおよびnon-constバージョンを提供できない理由はありません。


7

operator->()をオーバーロードすると(ここでは引数は渡されません)、コンパイラーが実際に行うのは、型への実際のポインターが返されるまで再帰的に呼び出します。次に、正しいメンバー/メソッドを使用します。

これは、たとえば、実際のポインターをカプセル化するスマートポインタークラスを作成する場合に便利です。オーバーロードされたoperator->が呼び出され、何が行われるか(たとえば、スレッドセーフのためのロック)、内部ポインターが返され、コンパイラーがこの内部ポインターに対して->を呼び出します。

誠実さについては、コメントやその他の回答で回答されています(両方提供できますが、両方提供する必要があります)。

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