6

私はC++の使用にまったく慣れていません。以前はJavaとActionScriptを扱っていましたが、今はこの強力な言語を学びたいと思っています。C ++はプログラマーにポインターを明示的に使用する機能を与えるので、私は矢印メンバー演算子の使用についてかなり混乱しています。これが私が書いてみたサンプルコードです。

main.cpp:

   #include <iostream>
   #include "Arrow.h"
   using namespace std;

   int main()
   {
        Arrow object;
        Arrow *pter = &object;

        object.printCrap(); //Using Dot Access
        pter->printCrap(); //Using Arrow Member Operator
        return 0;
   }

Arrow.cpp

   #include <iostream>
   #include "Arrow.h"
   using namespace std;

   Arrow::Arrow()
   {

   }

   void Arrow::printCrap(){
       cout << "Steak!" << endl;
   }

上記のコードでは、両方の方法(DotとArrow)を使用してステーキを印刷するだけです。

つまり、C ++を使用して実際の実用的なアプリケーションを作成する場合、矢印表記を使用するのはいつですか。以前のプログラミング経験からドット表記を使用することに慣れていますが、矢印はまったく新しいものです。

4

3 に答える 3

6

Cでは、a->bはと正確に同等(*a).bです。「矢印」表記は、便宜上導入されました。ポインタを介して構造体のメンバーにアクセスすることはかなり一般的であり、矢印表記は書き込み/入力が簡単であり、一般的にも読みやすいと考えられています。

ただし、C++では別のしわも追加されます。/operator->に対してオーバーロードされる可能性があります。それ以外はかなり珍しいことですが、そうすることはスマートポインタクラスでは一般的です(ほぼ必須です)。structclass

これ自体はそれほど珍しいことではありません。C++では、演算子の大部分をオーバーロードできます(ただし、、など、ほとんどの場合、オーバーロードする必要はありません)。operator&&operator||operator,

異常なのは、オーバーロードがどのようにoperator->解釈されるかです。まず、二項演算子のa->bように見えます->が、C ++でオーバーロードすると、単項演算子として扱われるため、正しい署名はT::operator()、ではなくT::operator(U)、その順序の何かになります。

結果もやや異常に解釈されます。fooをオーバーロードするあるタイプのオブジェクトであると仮定するとoperator->foo->barは意味として解釈され(f.operator->())->barます。これにより、オーバーロードされたのリターンタイプが制限されoperator->ます。具体的には、オーバーロードする別のクラスのインスタンスoperator->(またはそのようなオブジェクトへの参照)を返すか、ポインターを返す必要があります。

前者の場合、単純に見えるfoo->barということは、実際には、オブジェクトのインスタンスのチェーン全体(任意に長い)を「追跡」することを意味します。各インスタンスは、operator->という名前のメンバーを参照できる1つに到達するまで、それぞれがオーバーロードしbarます。(明らかに極端な)例として、次のことを考慮してください。

#include <iostream>

class int_proxy {
    int val;
public:
    int_proxy(): val(0) {}
    int_proxy &operator=(int n) { 
        std::cout<<"int_proxy::operator= called\n";
        val=n; 
        return *this; 
    }
};

struct fubar {
    int_proxy bar;
} instance;

struct h {
    fubar *operator->() {
        std::cout<<"used h::operator->\n";
        return &instance;
    }
};

struct g {
    h operator->() {
        std::cout<<"used g::operator->\n";
        return h();   
    }
};

struct f {
    g operator->() { 
        std::cout<<"Used f::operator->\n";
        return g();
    }
};

int main() {
    f foo;

    foo->bar=1;
}

ポインタを介したメンバーへの単純な割り当てのように見えfoo->bar=1;ますが、このプログラムは実際には次の出力を生成します。

Used f::operator->
used g::operator->
used h::operator->
int_proxy::operator= called

明らかに、この場合、単純なと同等でfoo->barはありません(それに近い場合でも)(*foo).bar。出力から明らかなように、コンパイラーは「隠し」コードを生成して->、さまざまなクラスのオーバーロードされた演算子のシリーズ全体をウォークスルーし、名前付きのメンバー(この場合はタイプでもありfooます)を持つもの(へのポインター)に到達しますbarこれはオーバーロードoperator=するため、割り当てからの出力も確認できます)。

于 2014-01-14T07:21:37.653 に答える
3

良い質問、

Dot(。) この演算子は、そのクラス/構造体のインスタンス変数を使用して、メンバー関数またはクラスまたは構造体のデータメンバーにアクセスするために使用されます。

object.function(); 
object.dataMember; //not a standard for class.

矢印(->)この演算子は、クラスまたは構造体のメンバー関数またはデータメンバーにアクセスするために使用されますが、そのクラス/構造体のポインターを使用します。

ptr->function();
ptr->datamember; //not a standard for class.
于 2012-10-23T04:04:25.513 に答える
2

->演算子は、間接参照されているポインターのメンバー関数を呼び出す方法です。(* pter).printCap()と書くこともできます。C ++は、クラスや本なしでは習得するのが難しいので、取得することをお勧めします。これは大きな投資になるでしょう。

于 2012-10-23T03:59:13.397 に答える