オブジェクトの構成要素である構造体とクラスは、連続したブロックとしてメモリに格納されます。ただし、実際のメモリ レイアウトとメンバー関数へのアクセスは、仮想関数の存在によって異なります。
構造体は C の構造体に似ていますが、C では次のようになります。デフォルトとして public メンバーを持つクラスと同等です。これらは、宣言の順序でメンバー アドレスが増加する連続したバイトとして格納されます。
たとえば、次の構造体:
struct MyStruct { int a; float b; char c; };
はメモリに次のように格納されます:
+---+---+---+ | a | b | c | +---+---+---+
メンバー関数にアクセスするために、コンパイラーはオブジェクトのアドレスをレジスター (通常はこれ) にロードし、オフセットを使用して特定のメンバーのアドレスをフェッチする命令を生成します。
クラスが仮想メンバー関数を持つ場合、クラスは構造体とは異なります。これに対応するために、vtable ポインターと呼ばれる追加のポインターが最初のメンバーとして保存されます。このポインタは、仮想関数のアドレスを含む関数テーブルを指します。
仮想関数が呼び出されるとき、vtable ポインタは適切な関数アドレスを取得するために使用されます。これにより、オブジェクトは動的タイプに基づいて仮想関数をさまざまに実装できます。
たとえば、次のクラス階層を考えてみましょう。
class Animal { public: virtual void speak(); }; class Dog : public Animal { public: void speak() override { cout << "Woof!"; } }; class Cat : public Animal { public: void speak() override { cout << "Meow!"; } };
Animal オブジェクトは次のようにメモリに格納されます。
+---+---+ | vtable | a | +---+---+
ここで、vtable は、すべての派生クラスの speech() の関数ポインターを含むテーブルを指します。
コンパイラーは、さまざまな方法でオブジェクト処理を最適化できます。インラインメンバー関数も含まれます。たとえば、構造体を返す単純なインライン関数は、すべてのメンバーをレジスタに保持し、メモリ割り当てをスキップして、完全に最適化できます。
要約すると、x86 アセンブリ内のオブジェクトは、メンバー アクセスを備えた連続ブロックとしてメモリに格納されます。構造体のオフセットまたはクラスの仮想関数テーブルによって容易になります。コンパイラーは、メンバー関数のインライン化や小さな構造体をレジスターに保持するなど、パフォーマンスを向上させるための最適化を採用します。
以上が仮想関数は、x86 アセンブリのオブジェクト ストレージとメンバー アクセスにどのような影響を与えますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。