48

ここに小さなテストプログラムがあります:

#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. 正しいとすれば、それはなぜですか。なぜそれが許可されるのかわかりませんか、それともテンプレートで「静的かどうか」メソッドを使用するのに役立つのでしょうか?
4

4 に答える 4

77

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

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
}
于 2008-11-28T11:43:53.160 に答える
18

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

k.DoCrash();

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

Test::DoCrash();

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

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

于 2008-11-28T11:49:10.670 に答える
4

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

いくつかのシナリオで役立つ可能性があります。

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

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

    • 関数がインスタンス固有のデータを必要とするものからそれを必要としないものに進化した場合 - したがって、staticインスタンスを使用しない簡単な使用を可能にし、インスタンス データの偶発的な使用を防ぐように作成されている場合 - 既存のクライアントの使用のすべてのポイントを面倒に更新する必要はありません。

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

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

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

于 2015-06-30T06:41:16.480 に答える
2

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

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

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

于 2008-11-28T11:42:35.050 に答える