また、次のコードで関数の前に「&」を使用する必要があるのはなぜですか?
void (Mammal::*pFunc) () const=0;
pFunc=&Mammal::Move;
Move() は基本クラスの仮想関数で、pFunc はこのクラスの仮想関数へのポインタです。では、なぜ「&」を使用する必要があるのでしょうか。仮想関数のいくつかの特別なプロパティによると? それとも単に構文ですか?
通常の関数はそのアドレスだけで呼び出すことができるため、通常の関数へのポインターは単なるアドレスです。
非仮想関数は、そのアドレスだけで呼び出すこともできます (もちろん、this
コンパイラが使用するメカニズムによって渡されるポインターも)。そのため、非仮想関数へのポインターは単なるアドレスになる可能性があります。
仮想関数は、コンパイラ固有のメカニズム (通常は、オブジェクト内の既知のオフセットにある vtable; 関数のアドレスは、テーブルへのインデックス付けによって検出されます) によって検索される必要があり、仮想関数へのポインターには、オブジェクトの実際のタイプに応じて、呼び出す実際の関数を決定するために必要な情報。
ただし、メンバー関数へのポインターは、仮想関数と非仮想関数の両方を処理できる必要があるため、両方の適切なメカニズムに十分な余地があり、ランタイム呼び出しは格納されたデータをチェックして何をすべきかを判断します。
一部のコンパイラは代替手段を提供しています。仮想関数へのポインタをポインタに絶対に、積極的に格納しないことを約束すると、コンパイラはより小さなポインタ表現を生成し、後で問題が発生することがわかります。あなたはその約束を破ります。
が必要な理由については、&
必須です。Microsoft の初期の C++ コンパイラは&
、クラス名を必要としませんでした (クラス名を必要としませんでした。省略した場合、現在のオブジェクトのクラスのメンバー関数へのポインターが取得されます)。彼らはルールを廃止することを提案することについて話しましたが、それはどこにも行きませんでした.