0
#include <iostream>

class Test {
public:
    int i;
    void print()
    {
        std::cout << "Hello" << std::endl;
    }
};

int main()
{
    class Test *p = NULL;
    p->print();
    (*p).print();
}

Output:

Hello
Hello

オブジェクトのメソッドとメンバー変数はメモリ内の別の場所に格納されていることを理解していますが、いつ呼び出しを解決できるかとしてp割り当てられますNULLTest::print()

Test6:~ 1001> g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-46)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Test6:~ 1002> g++ manoj.cpp
Test6:~ 1003> ./a.out
Hello
Hello
Test6:~ 1004> cat manoj.cpp
#include <iostream>

class Test {
public:
int i;
void print()
{
std::cout << "Hello" << std::endl;
}
};

int main()
{
class Test *p = NULL;
p->print();
(*p).print();
}
Test6:~ 1005>
4

3 に答える 3

3

クラスに仮想関数がない限り (つまり、コンパイラが vtable を作成しない)、メソッドへのすべてのポインタがプログラムにハードコードされるため、変数情報は必要ありません。ただし、その場合でも、有効なthisポインターがないため、クラッシュします。

于 2011-11-17T05:14:19.897 に答える
0

あなたは単にこれを行うことはできません. このコードはコンパイルされず、null ポインターをアドレス指定できません。使用してみてください:

int main()
{
    // no need for 'class' keyword when declaring the pointer:
    Test* p = new Test(); // use default constructor provided by compiler
    p->print();
    (*p).print();
    // you also need to delete the pointer before returning, but that's irrelevant
    return 0; // you need this too
}
于 2011-11-17T05:14:38.217 に答える
0

あなたがしたことは「適切に開発されたコード」ではありませんが、 this ポインターが null であっても、(明示的または暗黙的に) 逆参照していないため、機能します。

あなたの *p (または p->) はクラスTestであり、Test::printTest 内の何も参照していないため、... null の Testは常にTestであり、その内容を気にしないため、コードはコンパイルされて機能します.

ただし、このコードは次の場合に問題が発生します。

  • Test::printは仮想化されます。この場合p->print()(または(*p).print()) は、実際のオブジェクトの v テーブルを調べて、呼び出す関数を検出する必要があります。(派生した*pものであれば何でもTestかまいません) が、オブジェクトがないため、v-table を検出できず、プログラムがクラッシュします。
  • Testメンバーを持つように作成され、print関数はそれを出力するように作成されます。この場合、p無効なメモリブロックを指すため、関数はメンバー変数にアクセスする際に、null this ポインターを暗黙的に逆参照して、メンバーの場所を計算しようとします。は。また、メモリアドレスが無効になり、クラッシュが発生します。

実際、「未定義の動作」と呼ばれる灰色の領域に入ったところです。言語弁護士 (仕様を書いた人) はそれについて何も言いません (特に: 決して言わなかった「逆参照するのは (実行時) エラーです) 」無効なポインター": 彼らは、「無効なポインターを逆参照すると、未定義の動作が発生する」と述べましたが、これは「何が起こるべきかを教えたくない」ことをほとんど意味しません)。

しかし、コンパイラの作成者は何かをしなければならないため (コンパイラは「未定義」にすることはできません)、コンパイル時 (コード行の変換中) にポインターの値がどうなるかを知ることができないため、コードを任意の値に変換することにしました。仕方。

また、コードの実行はプロセス境界を壊さないため、クラッシュしません。また、「処理中の初期化されていない領域」にアクセスしないため、乱雑な値は見られず、すべて問題ないように見えます。

アンマネージ言語という言葉へようこそ!

于 2011-11-17T07:39:14.430 に答える