web-dev-qa-db-ja.com

クラスインスタンスでのC ++静的メンバーメソッド呼び出し

以下に小さなテストプログラムを示します。

#include <iostream>

class Test
{
public:
    static void DoCrash(){ std::cout<< "TEST IT!"<< std::endl; }
};

int main()
{
    Test k;
    k.DoCrash(); // calling a static method like a member method...

    std::system("pause");

    return 0;
}

VS2008 + SP1(vc9)では正常にコンパイルされます。コンソールには「TEST IT!」と表示されます。

私の知る限り、静的メンバーメソッドはインスタンス化されたオブジェクトで呼び出されるべきではありません。

  1. 私が間違っている?このコードは標準的な観点から正しいですか?
  2. 正しい場合、それはなぜですか?許可される理由がわかりません。または、テンプレートで「静的または非静的」メソッドを使用するのに役立つかもしれません。
38
Klaim

標準では、インスタンスを介してメソッドを呼び出す必要はない、と言うことはできないというわけではありません。それが使用される例さえあります:

C++ 03、9.4静的メンバー

クラスXの静的メンバーsは、修飾ID式X :: sを使用して参照できます。クラスメンバーアクセス構文(5.2.5)を使用して静的メンバーを参照する必要はありません。静的メンバーは、クラスメンバーアクセス構文を使用して参照できます。この場合、object-expressionが評価されます。

class process {
public:
   static void reschedule();
};

process& g();

void f()
{
   process::reschedule(); // OK: no object necessary             
   g().reschedule(); // g() is called
}

静的関数は呼び出されるためにインスタンス化されたオブジェクトを必要としません。

k.DoCrash();

とまったく同じように動作します

Test::DoCrash();

スコープ解決演算子(::)を使用して、クラス内の静的関数を決定します。

どちらの場合も、静的関数が必要としないため、コンパイラはthisポインターをスタックに入れないことに注意してください。

11
jab

2)正しい場合、それはなぜですか?許可される理由がわかりません。または、テンプレートで「静的または非静的」メソッドを使用するのに役立つかもしれません。

これは、いくつかのシナリオで潜在的に有用です。

  • [テンプレートの '"静的または非"メソッド]:]テンプレートに多くの型を指定でき、テンプレートがメンバーを呼び出したい場合:静的関数を提供する型メンバー関数と同じ表記法を使用して呼び出すことができます-前者はより効率的である可能性があり(パス/バインドへのthisポインタなし)、後者はポリモーフィック(virtual)ディスパッチおよび使用を許可しますメンバーデータ

  • コードのメンテナンスを最小限に抑える

    • 関数がインスタンス固有のデータの必要性から不要に進化した場合-したがって、staticを使用してインスタンスを簡単に使用でき、インスタンスデータの偶発的な使用を防ぎます-既存のクライアント使用のすべてのポイントは面倒に更新する必要があります

    • 型が変更された場合、var.f()呼び出しは引き続きvar型の関数を使用しますが、Type::f()は手動で修正する必要があります

  • 値を返す式または関数呼び出しがあり、(潜在的または常に)static関数を呼び出す場合、.表記により、decltypeまたは::表記を使用できるように、型にアクセスするためのテンプレートをサポート

  • 変数名は、はるかに短く、より便利であるか、より自己文書化された方法で命名されている場合があります

3
Tony Delroy

静的メソッドは、Javaで実行できるように、クラスのオブジェクトを使用して呼び出すこともできます。それでも、これを行うべきではありません。 Test::DoCrash();のようなスコープ演算子を使用します

namespace Test {
    void DoCrash() {
        std::cout << "Crashed!!" << std::endl;
    }
};

関数が呼び出し元のスコープにusing directive/declarationを使用して明示的にインポートされていない場合にのみ、そのネームスペースの外部からTest::DoCrash();によって呼び出すことができます。