7

ファイルに書き込まれるデータを表すために構造体を使用します。この構造体にメンバーを追加する必要がある場合(つまり、余分なデータを保存する必要がある場合)、元の構造体から派生した新しい構造体(これはデータセットの新しいバージョンを表します)を作成します。したがって、たとえば:

struct data1
{
   int stuff1;
   int stuff2;
};

struct data : data1
{
   int stuff3;
};

下位互換性は、ロードしているかどうかを確認し、ロードしている場合はdata1、に変換することで維持されますdata(そして、の新しいメンバーのみを値初期化しますdata)。これを行うための最良の方法は何でしょうか?これが私が始めたものです:

if( loaded_data.size() == sizeof(data1) ) {
    // Old data format detected, upgrade to new structure
    data d = data(); // value-initialize everything
    // TODO: Assign 'data1' to 'data'
}

dataからコピーするためにコンストラクターを入れることを考えましたdata1が、それは私が取得した自由な値の初期化を壊します(その時点で独自のデフォルトコンストラクターを実装する必要があります)。memcpy()を使用する必要がありますか、それともより優れた組み込みの方法がありますか(おそらくコピーセマンティクスのトリック)?

4

4 に答える 4

4
#include <cstdio>

struct A {
  int a;
};

struct B : A {
  int b;
};

int main()
{
  A a;
  a.a = 42; 
  B b;
  b.a = 0;
  b.b = 42;
  (A&)b = a;

  printf("%s\n", b.a == b.b?"it works":"nope");
}
于 2017-09-13T08:13:41.660 に答える
2

私はデザインが好きではありません。継承すべきではないと思います(たとえば、これによりタイプが集計になりません)。エンティティのサイズをチェックするよりも、シリアル化/逆シリアル化の方が優れたアプローチがあると思います。そうは言っても、初期化を強制した後は、割り当てることができます。暗黙的に宣言されたコピーコンストラクターが定義され、メンバーがコピーされます。

data d = { 1, 2 };         // Can use this as it is an aggregate
data1 d1 = data1();
d1 = d;

繰り返しますが、私はこれを完全に避けます...

継承の代わりに構成を使用した場合は、集約初期化を使用して、ベースの二重初期化を回避できますdata1

struct data1 {
  data base;
  int extra;
};
data d   = { 1, 2 };
data1 d1 = { d, 5 };   // or { d, 0 }

data1からコピーするために、データにコンストラクターを配置することを考えましたが、それでは、取得した自由な値の初期化が壊れます(その時点で、独自のコピーとデフォルトのコンストラクターを実装する必要があります)。

完全に真実ではありません。dataコンストラクターを取る存在はデフォルトコンストラクターの暗黙の宣言を禁止するため、デフォルトコンストラクターを提供する必要があります。ただし、コピーコンストラクターは引き続き暗黙的に生成されます。

于 2012-09-18T19:37:58.453 に答える
1

メンバーにデフォルトのctorを設定したいが、それでもデフォルトのcopyctorを利用できるようにしたい。作曲でこれができると思います。

struct Data1 {
  /**/
};

struct Data2 { // this is your extension
  /**/
};

struct Data3 { // possibly the next extension.
  /**/
};

template <typename Base, typename Derived>
struct ExtendData : Base, Derived {
  ExtendData(Base const& base, Derived const& derived)
    : Base(base), Derived(derived) {}
};

typedef ExtenData<Data1,Data2> FullData2;
typedef ExtenData<FullData2,Data3> FullData3;

これにより、PODのすべてのデフォルトコンストラクターを使用できますstruct

FullData2 data2 = {Base{/**/},Derived{/**/}};
于 2012-09-18T19:43:30.870 に答える
0

の醜さを回避/非表示にするmemcpy()場合は、グローバル関数を作成して構造を初期化できます。これらの関数内でmemcpy()、フィールドを1つずつ使用または割り当てることができます。

このように、初期化セマンティクスが変更された場合でも、初期化関数を更新するだけで、構造体からメンバー関数を削除できます(つまり、必要に応じて、単純なデータ構造体のように見えます)。例えば:

void InitData ( data& oData, data1& oInitializer )
{
    memcpy ( ... );
}

新しいメンバーと新しい構造を追加し続けると、新しいタイプごとにこの関数をオーバーライドできます。

(やや)C ++に似たアプローチが必要な場合は、これらの関数を構造体のパブリック静的メンバーに変えることができますdata。あなたはそれを次のようなものと呼ぶでしょう

data::InitFrom ( data1 );

これにより、構造をクリーンに保つことができます(仮想関数などはありません)が、型の安全性は向上し、低レベルの詳細はコードの他の部分から隠されます。これらのgloal/static関数は、構造の現在のセマティックも保持します。

ただし、C++の純粋主義者はおそらくこのオプションを嫌うことを覚えておいてください。

于 2012-09-18T19:43:38.437 に答える