22

それで私はクラスについて学んでいて、私が見つけた何かに出くわしたのは私にとってかなり厄介でした。

class Nebla 
{
    public:
        int test()
        {
            printout();
            return x;
        }

        void printout()
        {
            printout2();
        }

    private:
        int x,y;
        void printout2()
        {
            cout<<"Testing my class";
        }
};

クラスでは、関数を宣言する前に関数を使用できることがわかりました(プロトタイプを作成します)。

あなたは私がdeclerationprintout()の前に使用したのを見ることができます。printout2()

そして、宣言する前に変数を使用することもできます

あなたは私がしたのを見ることができますreturn x; xを宣言する前に。

宣言前にクラスで関数と変数を使用できるのに、クラス外で使用するとエラーが発生するのはなぜですか?

ありがとう

4

4 に答える 4

24

良い質問; 私は何年も考えずにその機能に頼ってきました。Stroustrup のThe C++ Programming LanguageThe Annotated C++ Reference Manualなど、いくつかの C++ の本を調べて答えを見つけましたが、違いを認めたり説明したりするものはありません。しかし、私はそれを通して推論できると思います。

あなたの例が機能する理由は、あなたのtestとの本体がprintout実際にはファイルに表示される場所ではないからだと思います。コード

class MyClass {
  void someFun() {
    x = 5;
  }
  int x;
};

...変数を使用する前に変数を宣言する必要があるという規則に違反しているように見えますが、実際には次と同等です。

class MyClass {
  void someFun();
  int x;
};

void MyClass::someFun() {
  x = 5;
}

MyClassそのように書き直すと、定義内のものは実際には宣言のリストであることが明らかになります。そして、それらは任意の順序にすることができます。xそれが宣言されるまで、あなたは依存していません。私はこれが真実であることを知っています。

void MyClass::someFun() {
  x = 5;
}

class MyClass {
  void someFun();
  int x;
};

...それはもはやコンパイルされません! したがって、クラス定義が (メンバーの完全なリストと共に) 最初に来て、メソッドは、クラスで宣言された順序に関係なく、任意のメンバーを使用できます。

パズルの最後のピースは、C++ ではクラス定義の外でクラス メンバーを宣言することを禁止しているため、コンパイラがクラス定義を処理すると、クラス メンバーの完全なリストを認識します。これは、Stroustrup の The Annotated C++ Reference Manual の p.170 で次のように述べられています

これを調査していただきありがとうございます。今日、私は何か新しいことを学びました。:)

于 2012-10-26T22:11:56.530 に答える
10

明確にするために、これは、いくつかのコンパイラがクラス定義を処理する方法だけでなく、C++ 標準で必要とされています。

N3242 3.3.7:

クラスで宣言された名前の潜在的なスコープは、名前の宣言ポイントに続く宣言領域だけでなく、すべての関数本体、非静的データ メンバーのブレースまたはイコール初期化子、およびその中のデフォルト引数からも構成されます。クラス(ネストされたクラスのそのようなものを含む)。

于 2012-10-26T22:19:08.007 に答える
1

フィリップの良い反応に加えて、Stroustrupは、C++の設計と進化における名前検索ルールの優れた説明を提供します。これについては、「6.3説明」で説明しています。6.3.1.1 「ARM名ルックアップルール」では、 ARMで定義されている2つのルールについて言及しています。

[1]型の再定義規則:型名は、クラスで使用された後、クラスで再定義することはできません。

[2]書き換えルール:インラインで定義されたメンバー関数は、クラス宣言の終了直後に定義されたかのように分析されます。

したがって、あなたの場合、(Philipが推測したように)書き換えルールが適用されます。そのため、これらのクラスメンバーを転送参照できます。

この本は主に歴史的な興味があるかもしれませんが(94年に書かれました)、それらの規則は今日も同じように適用されていると思います。

于 2012-10-26T23:35:29.580 に答える
0

これができる理由はtest、 、printoutまたはを呼び出すまでにprintout2、それらがすでに作成されているためです。実装前に任意の関数の外部で関数を呼び出すと、エラーが発生します。

クラス メンバー関数は、クラスの残りの評価の流れとは非同期であると考えてください。これはスタンドアロン関数では機能しませんが、まだインスタンス化されていないデータ メンバーにアクセスできます。なぜこれができるのか完全にはわかりませんが、クラス オブジェクトのインスタンス化に関係していると思います。

于 2012-10-26T21:50:15.517 に答える