特に、ほとんどの C++ 実装が機能する方法は、基本クラスのサイズを変更すると、すべての派生クラスの再コンパイルが必要になることを意味します。
このステートメントは stroustrup book からのものです。基本クラスが.so
ファイルにあり、メンバー関数の実装を変更するだけの場合、その共有オブジェクトにリンクされたプログラムを再コンパイルする必要がないということですか?
特に、ほとんどの C++ 実装が機能する方法は、基本クラスのサイズを変更すると、すべての派生クラスの再コンパイルが必要になることを意味します。
このステートメントは stroustrup book からのものです。基本クラスが.so
ファイルにあり、メンバー関数の実装を変更するだけの場合、その共有オブジェクトにリンクされたプログラムを再コンパイルする必要がないということですか?
正式には、再コンパイルしないと、One Definition Rule に違反し、未定義の動作が発生します。
実際には、変更するメンバー関数がどこにもインライン化されておらず、署名を変更していない限り、おそらくバイナリ互換性が保持されます。ほとんどのプラットフォームで。運が良ければ、プラットフォームのドキュメントでそのような保証が提供されます。
あなたの理解は正しいと思います。メンバー関数の本体を変更するだけでは、そのオブジェクトのインスタンスに必要なスペースの量は変わりません。コードはオブジェクト インスタンスの "中に" 格納されません。データのみです。
クラスがコンパイルされると、メンバー データ フィールドへの参照は、そのオブジェクト データの先頭からのオフセットになります。また、派生クラスのデータは通常、基本クラスのデータの後に配置されます。そのため、基本クラスにフィールドを追加すると、派生クラス データの正しいオフセットがすべて変更されます。これは、新しい (正しい) オフセットを指すように、基本クラスを再コンパイルする必要があることを意味します。
前
class Foo {
int a; // offset 0 (assuming no vtable)
}
class Bar : public Foo {
int b; // offset 4
}
Bar bar; bar.b = 7; // sets the 32-bit value at this+4 to 7
後
class Foo {
int a; // offset 0
int c; // offset 4
}
class Bar : public Foo {
int b; // offset 8
}
Bar b; bar.b = 7; // Without recompiling: sets the 32-bit value at this+4
// which is actually where Foo.a is stored!
// With recompiling: sets the 32-bit value at this+8
実装だけであれば、問題なく動作するはずです。これがWindowsDLLの全体的な概念です。インターフェイスを追加または削除しても、クラスサイズは変更されませんが(新しい仮想関数を導入する場合を除く)、大まかに言えば、メモリに配置される関数の変更方法が変更される可能性があります。そのため、新しい機能を使用する場合は、再コンパイルが必要です。一方、最新のコンパイラのほとんどは、ヘッダーファイルを簡単に変更できるため、関連する変更を識別するのに十分な機能を備えています。