驚くべきNULLクラスポインタ
一.NULLポインタ
NULLは、C/C++で空のポインタ、すなわちアドレスが0を指すポインタを表すのによく用いられる.
通常、ポインタが指す空間を初期化または解放した後、ポインタをNULLに設定し、懸濁ポインタが割り当てられた空間を指していないことを示すことを防止する.
こうして見るとNULLを指すポインタはそれだけ?
もちろん、Structの変数のオフセット位置を求めるなど、いくつかの小さなテクニックを使って実用的なことをします.
二.NULL空クラスポインタ
まずコードを見てみましょう.
△直感は、人間がこれまでの経験や現場の環境に基づいて迅速に判断し、ゆっくり分析した結果、必ずしも答えに近いとは限らない.
しかし、今回は確かに直感が間違っていて、プログラムが正常に動作し、スムーズに「Suprise」を印刷することができます.
三.空のクラスポインタの関数呼び出し解析
(1)サンプルコードをよく分析すると、Suprise()メンバー関数アドレスは不変(動的バインドを必要としない非虚関数)であり、コンパイル段階でpTestのポインタタイプに基づいてSuprise()関数呼び出しのアドレスが得られる.呼び出しを行い、アセンブリコードがより明確に証明されました.
虚関数の場合、オブジェクトを指す虚表ポインタと虚関数オフセットに基づいて、対応する関数ボディエントリを見つける必要があります.このプロセスは、動的バインドプロセスにもなります.
(2)(1)関数の正確な実行が保証されているほか,pTest->Supriseでメンバー変数が操作されていないという条件も隠されている.
Superise関数にはThisポインタが隠されているため、メンバー変数を操作していないため、ThisポインタがNULLであってもメモリアクセス競合エラーは発生しません.
以上を総合すると、Supriseの非虚関数と関数にはメンバー変数の操作がなく、NULLクラスポインタがメソッドの呼び出しに成功することを保証します.
NULLは、C/C++で空のポインタ、すなわちアドレスが0を指すポインタを表すのによく用いられる.
通常、ポインタが指す空間を初期化または解放した後、ポインタをNULLに設定し、懸濁ポインタが割り当てられた空間を指していないことを示すことを防止する.
こうして見るとNULLを指すポインタはそれだけ?
もちろん、Structの変数のオフセット位置を求めるなど、いくつかの小さなテクニックを使って実用的なことをします.
#define VALUEOFFSET(sType, vName) (int)(&((sType *)NULL)->vName)
空のポインタを指しても私たちのプログラムのためにこんなに多くのことをすることができて、本当に面白いです.私が出会った驚くべき問題も、NULLポインタと関係がある.二.NULL空クラスポインタ
まずコードを見てみましょう.
#include <iostream>
using namespace std;
class Base
{
public:
Base(){;}
void Suprise()
{
cout << "Suprise" << endl;
}
};
void main()
{
Base *pTest = NULL;
pTest->Suprise();
return;
}
このコードを慎重に読んだ後、正しい判断ができるかもしれませんが、最初の感覚では実行が間違っています.△直感は、人間がこれまでの経験や現場の環境に基づいて迅速に判断し、ゆっくり分析した結果、必ずしも答えに近いとは限らない.
しかし、今回は確かに直感が間違っていて、プログラムが正常に動作し、スムーズに「Suprise」を印刷することができます.
三.空のクラスポインタの関数呼び出し解析
(1)サンプルコードをよく分析すると、Suprise()メンバー関数アドレスは不変(動的バインドを必要としない非虚関数)であり、コンパイル段階でpTestのポインタタイプに基づいてSuprise()関数呼び出しのアドレスが得られる.呼び出しを行い、アセンブリコードがより明確に証明されました.
Base *pTest = NULL;
004119FE mov dword ptr [pTest],0
pTest->Suprise();
00411A05 mov ecx,dword ptr [pTest]
00411A08 call Base::Suprise (411032h)
虚関数の場合、オブジェクトを指す虚表ポインタと虚関数オフセットに基づいて、対応する関数ボディエントリを見つける必要があります.このプロセスは、動的バインドプロセスにもなります.
(2)(1)関数の正確な実行が保証されているほか,pTest->Supriseでメンバー変数が操作されていないという条件も隠されている.
Superise関数にはThisポインタが隠されているため、メンバー変数を操作していないため、ThisポインタがNULLであってもメモリアクセス競合エラーは発生しません.
void Suprise(Base * const this)
以上を総合すると、Supriseの非虚関数と関数にはメンバー変数の操作がなく、NULLクラスポインタがメソッドの呼び出しに成功することを保証します.