47

通常の演算子のオーバーロードを理解しています。コンパイラはそれらをメソッド呼び出しに直接変換できます。->演算子についてはよくわかりません。私は最初のカスタムイテレータを書いていましたが、->演算子が必要だと感じました。私はstlソースコードを見て、それのように自分自身を実装しました:

MyClass* MyClassIterator::operator->() const
{
    //m_iterator is a map<int, MyClass>::iterator in my code.
    return &(m_iterator->second);
}

次に、次のようなMyClassIteratorのインスタンスを使用できます。

myClassIterator->APublicMethodInMyClass().

コンパイラはここで2つのステップを実行するようです。1.->()メソッドを呼び出して、一時的なMyClass*変数を取得します。2.一時変数でAPublicMethodInMyClassを呼び出し、その->演算子を使用します。

私の理解は正しいですか?

4

2 に答える 2

95

operator->言語に特別なセマンティクスを持っており、オーバーロードされると、結果に再適用されます。残りの演算子は1回だけoperator->適用されますが、生のポインターに到達するために必要な回数だけコンパイラーによって適用され、そのポインターによって参照されるメモリーにアクセスするためにもう一度適用されます。

struct A { void foo(); };
struct B { A* operator->(); };
struct C { B operator->(); };
struct D { C operator->(); };
int main() {
   D d;
   d->foo();
}

前の例では、式d->foo()でコンパイラがオブジェクトを取得してd適用operator->し、タイプのオブジェクトを生成します。C次に、演算子を再適用して、のインスタンスをB取得し、再適用してに取得しますA*。その後、オブジェクトを逆参照します。指摘されたデータにアクセスします。

d->foo();
// expands to:
// (*d.operator->().operator->().operator->()).foo();
//   D            C            B           A*
于 2012-05-21T02:35:03.443 に答える
33
myClassIterator->APublicMethodInMyClass()

次のようなものです。

myClassIterator.operator->()->APublicMethodInMyClass()

オーバーロードされたものへの最初の呼び出しは、operator->と呼ばれるアクセス可能な(呼び出しサイトからの)メンバー関数を持つあるタイプのポインターを取得しますAPublicMethodInMyClass()APublicMethodInMyClass()もちろん、それが仮想であるかどうかに応じて、通常の関数ルックアップルールに従って解決します。

必ずしも一時変数はありません。コンパイラは、によって返されたポインタをコピーする場合としない場合があります&(m_iterator->second)。おそらく、これは最適化されます。ただし、タイプの一時オブジェクトはMyClass作成されません。

通常の警告は、次の場合にも当てはまりm_iteratorます。呼び出しが無効化されたイテレータにアクセスしないようにしてください(vectorたとえば、を使用している場合)。

于 2012-05-20T22:46:40.040 に答える