質問
次のようなクラスがある場合
class Example_Class
{
private:
int x;
int y;
public:
Example_Class()
{
x = 8;
y = 9;
}
~Example_Class()
{ }
};
そして次のような構造体
struct
{
int x;
int y;
} example_struct;
Example_Class
example_struct
のメモリ構造は
たとえば、次のような場合
struct example_struct foo_struct;
Example_Class foo_class = Example_Class();
memcpy(&foo_struct, &foo_class, sizeof(foo_struct));
は foo_struct.x = 8
および foo_struct.y = 9
(つまり、foo_classのx、y値と同じ値)になりますか?
私が尋ねる理由は、オブジェクトをCコードと共有しているC ++ライブラリ(変更したくない)があり、C ++ライブラリからのオブジェクトを表す構造体を使用することです。オブジェクトの属性にのみ興味があります。
理想的な状況は、CコードとC ++コードの間の一般的な構造の周りにExample_classラップを配置することですが、使用中のC ++ライブラリを変更するのは簡単ではありません。
解決
C ++標準保証は、C struct
およびC ++ class
(または struct
- -同じこと)は、C ++ class
/ struct
が POD (" Plain Old Data")であるという基準に適合する場合、同一になります。 PODはどういう意味ですか?
次の場合、クラスまたは構造体はPODです。
- すべてのデータメンバーはパブリックであり、それ自体がPODまたは基本型(ただし、参照またはメンバーへのポインター型ではない)、またはそのような配列です
- ユーザー定義のコンストラクタ、代入演算子、デストラクタはありません
- 仮想関数はありません
- 基本クラスはありません
唯一の" C ++-isms"について許可されるのは、非仮想メンバー関数、静的メンバー、およびメンバー関数です。
クラスにはコンストラクタとデストラクタの両方があるため、正式にはPOD型ではないため、保証は適用されません。 (ただし、他の人が述べたように、実際には、仮想関数がない限り、実際に2つのレイアウトはどのコンパイラでも同じになる可能性があります。)
のセクション[26.7]を参照してください。詳細については、C ++ FAQ Lite を参照してください。
他のヒント
example_structのメモリ内の構造は、Example_Classの構造と同様です
動作は保証されておらず、コンパイラに依存します。
とは言っても、Example_Classに仮想メソッドが含まれていない場合(そして基本クラスから継承しない場合)、答えは「はい、私のマシン上」です。
説明した場合、答えは「おそらくはい」です。ただし、クラスに仮想関数(基本クラスから継承できる仮想デストラクタを含む)がある場合、または多重継承を使用する場合、クラスレイアウトは異なる場合があります。
他の人が言ったことに追加するには(例:コンパイラ固有、仮想関数がない限り機能する可能性が高い):
これを行う場合は、sizeof(Example_class)== sizeof(example_struct)という静的なアサート(コンパイル時チェック)を強くお勧めします。 BOOST_STATIC_ASSERT、または同等のコンパイラ固有またはカスタムの構築を参照してください。誰か(またはコンパイラーの変更など)がクラスを変更して一致を無効にする場合、これは優れた防御の第一線です。追加のチェックが必要な場合は、メンバーへのオフセットが同じであることをランタイムでチェックすることもできます。これにより(静的サイズのアサートと共に)正確性が保証されます。
C ++コンパイラの初期には、コンパイラがクラスで構造体キーワードを最初に変更してからコンパイルする例がありました。類似点についてはあまりにも。
違いは、クラスの継承、特に仮想関数に由来します。クラスに仮想関数が含まれる場合、レイアウトの先頭に型記述子へのポインターが必要です。また、クラスBがクラスAから継承する場合、クラスAのレイアウトが最初に来て、クラスBの独自のレイアウトが続きます。
したがって、クラスインスタンスを構造体インスタンスにキャストするだけの質問に対する正確な答えは、クラスの内容に依存します。メソッド(コンストラクターと非仮想デストラクター)を持つ特定のクラスの場合、レイアウトはおそらく同じになります。デストラクタが仮想と宣言された場合、レイアウトは構造とクラス間で間違いなく異なるでしょう。
これは、C構造体からC ++クラスにステップするために行う必要があまりないことを示す記事です。レッスン1-構造からクラスへ
そして、ここに仮想関数を持つクラスに仮想関数テーブルが導入される方法を説明する記事があります:レッスン4-多態性
クラス& C ++の構造体は同等です。ただし、構造体のすべてのメンバーはデフォルトでパブリックです(クラスメンバーはデフォルトでプライベートです)。これにより、C ++コンパイラでのレガシーCコードのコンパイルが期待どおりに機能することが保証されます。
構造体ですべての派手なC ++機能を使用することを妨げるものは何もありません:
struct ReallyAClass
{
ReallyAClass();
virtual !ReallAClass();
/// etc etc etc
};
データをCに渡したいときに、クラスのメンバーを構造体に明示的に割り当てないのはなぜですか?そうすれば、コードがどこでも機能することがわかります。
おそらく、パブリックまたはプライベートのいずれかで、構造体からクラスを派生させるだけです。その後、キャストするとC ++コードで正しく解決されます。