C++クラスの空のポインターは、メンバー関数のコードを呼び出します。


クラスの実例はメンバー関数を呼び出す原理です。
実際には、オブジェクトのインスタンスまたはポインタのインスタンスを介して呼び出しても、実際には、下の階の呼び出しのプロセスは同じであり、現在のオブジェクトのポインタをパラメータとして呼び出しられたメンバー関数に渡すことである。以下の関連実例コードによって検証される:
実験のC++コード

class Student
{
private:
 int age;
public:
 Student() {}
 Student(int age) : age(age) {}
 int getAge() { return this->age; }
};
 
int main(int argc, char const *argv[])
{
 Student s(10);
 int age = s.getAge();
 
 Student* ps = new Student(10);
 age = ps->getAge();
 
 return 0;
}
VSL 2015デバッグ機能に基づく反アセンブリコード

int main(int argc, char const *argv[])
{
00A41860 push  ebp 
00A41861 mov   ebp,esp 
00A41863 push  0FFFFFFFFh 
00A41865 push  0A461D2h 
00A4186A mov   eax,dword ptr fs:[00000000h] 
00A41870 push  eax 
00A41871 sub   esp,104h 
00A41877 push  ebx 
00A41878 push  esi 
00A41879 push  edi 
00A4187A lea   edi,[ebp-110h] 
00A41880 mov   ecx,41h 
00A41885 mov   eax,0CCCCCCCCh 
00A4188A rep stos dword ptr es:[edi] 
00A4188C mov   eax,dword ptr [__security_cookie (0A4B004h)] 
00A41891 xor   eax,ebp 
00A41893 mov   dword ptr [ebp-10h],eax 
00A41896 push  eax 
00A41897 lea   eax,[ebp-0Ch] 
00A4189A mov   dword ptr fs:[00000000h],eax 
 Student s(10);
00A418A0 push  0Ah /*         : 10 */
00A418A2 lea   ecx,[s] /*   s     ,       ECX*/
00A418A5 call  Student::Student (0A4103Ch) /*        0A4103Ch     */
 int age = s.getAge();
00A418AA lea   ecx,[s] /*   s     ,       ECX*/
00A418AD call  Student::getAge (0A412D5h) /*        0A412D5h     */
00A418B2 mov   dword ptr [age],eax /*            age*/
 
 Student* ps = new Student(10);
00A418B5 push  4 /*          ,   int    ,  4  (32   )*/
00A418B7 call  operator new (0A412A3h) /*           ,  C malloc  */
00A418BC add   esp,4 /*   4   ,    operator new            */
00A418BF mov   dword ptr [ebp-108h],eax /*eax           ,   ptr [ebp-108h]         */
00A418C5 mov   dword ptr [ebp-4],0 
00A418CC cmp   dword ptr [ebp-108h],0 
00A418D3 je   main+8Ah (0A418EAh) /*      ,        0,   ,   0A418EAh*/
00A418D5 push  0Ah /*          : 10*/
00A418D7 mov   ecx,dword ptr [ebp-108h] /*   ps                  ECX*/
00A418DD call  Student::Student (0A4103Ch) /*         0A4103Ch      */
00A418E2 mov   dword ptr [ebp-110h],eax 
00A418E8 jmp   main+94h (0A418F4h) 
00A418EA mov   dword ptr [ebp-110h],0 
00A418F4 mov   eax,dword ptr [ebp-110h] 
00A418FA mov   dword ptr [ebp-0FCh],eax 
00A41900 mov   dword ptr [ebp-4],0FFFFFFFFh 
00A41907 mov   ecx,dword ptr [ebp-0FCh] 
00A4190D mov   dword ptr [ps],ecx 
 age = ps->getAge();
00A41910 mov   ecx,dword ptr [ps] /*   s             ECX*/
00A41913 call  Student::getAge (0A412D5h) /*         0A412D5h      */
 age = ps->getAge();
00A41918 mov   dword ptr [age],eax 
 
 return 0;
00A4191B xor   eax,eax 
}
分析
ソースコードとコンパイルコードの対比を通じて、実はメンバー関数とクラスの実例はバインディング関係がないので、メンバー関数はクラスに属しています。メモリの中には有効なメモリアドレスだけがあります。メンバ関数については、インスタンスが必要であり、レジスタECXを介して渡される。
ここで考えさせてください。なぜスタックを通して伝達しないですか?
まず、スタックはメモリに位置していますが、レジスタはCPUに位置しています。この2つの読み書き速度は違います。これは効率の最適化です。また、約束が現在のメンバー関数の中にある場合は、ECXレジスタを変更しないと良いです。
しかし、スタックを使用して転送する場合、スタックはダイナミックメモリ空間であるため、現在のインスタンスのアドレスを追跡して維持するのに不便であり、たとえEBPとESPを使用してメンテナンスしても、オフセット量を加算する必要があり、これは読み書き効率に負担をかける。メンテナンスがうまくいかないと、データが乱れます。ここは全部個人分析です。間違いがあれば指摘してもいいです。
タイトルを返す
したがって、タイトルに戻ります。クラスの空のポインタがメンバー関数を呼び出したら、コンパイルが通ります。次に運行中に、二つの状況に分けます。
一、呼び出しられたメンバー関数では、現在のインスタンスのメンバー変数を呼び出さない場合、プログラムは正常に実行されます。

class Student
{
private:
 int age;
public:
 Student() {}
 Student(int age) : age(age) {}
 void eat() {}
};
 
int main(int argc, char const *argv[])
{
 Student* ps = nullptr;
 ps->eat();
 return 0;
}
二、呼び出されたメンバー関数では、現在のインスタンスのメンバー変数を読むためにthisポインタを使用した場合、まず呼び出しはメンバー関数が成功的に呼び出され、コードの実行はメンバー関数の領空に入りましたが、コードが現在のインスタンスを読み書きするメンバー変数に実行されるとメモリアクセスが異常になります。
最後に発散して考える
その中の一つの言叶を思い出します。メンバー関数はクラスに属しています。実例ではなく、あなたの思考を引き起こしますか?クラスの静态関数もクラスに属しています。上のコード:

#include <iostream>
using namespace std;
 
class Student
{
private:
 int age;
public:
 Student() {}
 Student(int age) : age(age) {}
 static int classtime() {
  return 9;
 }
 void eat() {}
};
 
int main(int argc, char const *argv[])
{
 Student* ps = nullptr;
 int time = ps->classtime();
 cout << time << endl;
 return 0;
}
実験を通してこのコードは成功的に実行できることがわかった。原理は上に述べましたが、ここでは詳しく説明しません。主な点はクラスの静的関数が特定のインスタンスのメンバデータに絶対に動作しないため、このような呼び出しは安全である。実際のプログラミングでは、この方法は使えないでしょう。
締め括りをつける
面接の時に聞かれました。自分でできますが、はっきり答えられないのも罪です。ここでまとめます。
ここでは、C++クラスの空のポインターは、メンバー関数を呼び出す記事を紹介します。より多くの関連C++クラスの空のポインターは、メンバー関数の内容を呼び出します。私たちの以前の記事を検索したり、次の関連記事を見たりしてください。これからもよろしくお願いします。