-6

内部的には、クラスの C++ メソッドは、最初のパラメーターがクラスまたは構造体のインスタンスである C 関数のようなものです。

例えば:

void Foo::Do();

C の次の宣言と同等です。

void Do(Foo* this);

したがって、メソッド内からメンバ m_someMember を使用することは、C 関数内から this->m_someMember を使用するようなものです。

長年の C/C++ プログラミング経験の後、私はつい最近自問自答しました。

私の推測では、メソッドがまったくメンバーを参照していない場合、なぜクラッシュするのでしょうか?

そこで、簡単なテストを行いました (Windows プラットフォームで、Visual C++ 2008 を使用):

class Foo
{
public:
    Foo() {}
    virtual ~Foo() {}

    void Do();
};

void Foo::Do()
{
    cout << "Calling 'Do' for " << this << endl;
}


int _tmain(int argc, _TCHAR* argv[])
{
    Foo foo;
    foo.Do();

    Foo* pNullFoo = 0;
    pNullFoo->Do();

    return 0;
}

次のような出力が得られます。

Calling 'Do' for 0038FE5C
Calling 'Do' for 00000000

これは、null であるインスタンス ポインターに対するクラッシュの事後デバッグを行うときに面倒になる可能性があります。これが無効だと、このメソッドを呼び出せないと思うかもしれません。

一方、メソッドが仮想として宣言されている場合:

virtual void Foo::Do() { ... }

次に、行:

pNullFoo->Do();

ページ フォールト例外が発生します。なんで?仮想メソッドを持つクラスのインスタンスには、それらが属する子クラスの仮想メソッドへの vtable へのポインターがあるためです。したがって、コンパイラが最初に行うことは、pNullFoo がその vtable メンバーにアクセスできるようにすることです。

結論として、これは Do のような非コンテキスト関数をメソッドよりも手続き型ルーチンとして実装する方が良い設計です。

4

2 に答える 2

2

メンバー データにアクセスする必要のないメンバー関数の適切な設計は、静的として定義することです。

static void Do();

次に、次のように呼び出します。

Foo::Do();

そして、それを行うためにオブジェクトやポインターを用意する必要さえありません。

于 2013-08-28T18:31:29.637 に答える