Theolizer
Version.1.2.0
serializer for C++ / Do you want to update your classes easily ?
|
ここでは、保存先指定について説明します。
クラスや構造体に含まれるメンバ変数をシリアライズするかしないか指定できます。 指定方法は2種類あります。 侵入型半自動クラスについて指定可能です。(*1)
Theolizerは、クラスを複数のファイルや通信先に分割して保存/回復できます。
そのためには
これにより、2と3で指定された保存先集合間に共通な保存先がある場合、2のメンバ変数が3で生成したシリアライザに渡したstreamへ保存、streamから回復されます。
なお、両者とも保存先を明示的に指定しなかった場合、「保存先無し」の意味ではなく「全ての保存先」の意味になります。2に保存先を明示的に指定していない場合、3でどの保存先を指定しても常にシリアライズされます。また、3で保存先を明示的に指定していない場合、2にどの保存先を指定していても常にシリアライズされます。
THEOLIZER_DESTINATIONS()マクロで定義します。
通常のenum型の定義と同じく、保存先を用いる場所全てより前に定義して下さい。
構文は次の通りです。
THEOLIZER_DESTINATIONS(前THEOLIZER_DESTINATIONS()マクロ最後の保存先, 保存先0, 保存先1, ... );
マクロ展開の都合上、THEOLIZER_DESTINATIONS()1つで最大8つの保存先を定義できます。8つを超える保存先を定義したい場合、THEOLIZER_DESTINATIONS()を続けて記述して下さい。例えは保存先を12個定義したい場合は、下記のようになります。
シンボルはAll以外を自由に使って頂いて良いです。文字はenum型のシンボル名に使えるものを全て使えます。
なお、Allは事前定義しています。「全ての保存先」の意味を持ち、内部的に使用しています。
また、各保存先はtheolizer::destination名前空間に配置されます。また、この名前空間にはtheolizerDの別名を定義しています。例えばDest1はtheolizerD::Dest1として指定します。
2.侵入型半自動クラス をTHEOLIZER_INTRUSIVE()マクロで指定しますが、その先頭パラメータで指定します。
デフォルト保存クラス :THEOLIZER_INTRUSIVE(CS, (クラス名), バージョン番号);
デフォルト非保存クラス:THEOLIZER_INTRUSIVE(CN, (クラス名), バージョン番号);
メンバ変数への指定にはTHEOLIZER_ANNOTATE()マクロをメンバ変数定義の最後、;の前に書きます。
保存しない:THEOLIZER_ANNOTATE(FN)
保存する :THEOLIZER_ANNOTATE(FS)
保存し、保存先も指定する:THEOLIZER_ANNOTATE(FS:<保存先のリスト>
))
シリアライザ名<保存先のリスト> インスタンス名(パラメータ);
の構文で指定します。
デフォルト保存クラス例 (source/reference_and_test/basic2/test_destinations.h)
説明:
メンバ変数 | 指定 | 説明 |
---|---|---|
mNoAnnotate | 指定無し | デフォルト保存クラスなので、シリアライズされます |
mAnnotateSave | 保存する | シリアライズされます |
mAnnotateNonSave | 保存しない | シリアライズされません |
デフォルト非保存クラス例 (source/reference_and_test/basic2/test_destinations.h)
説明:
メンバ変数 | 指定 | 説明 |
---|---|---|
mNoAnnotate | 指定無し | デフォルト非保存クラスなので、シリアライズされません |
mAnnotateSave | 保存する | シリアライズされます |
mAnnotateNonSave | 保存しない | シリアライズされません |
保存と回復ソース:(source/reference_and_test/basic2/test_destinations.cpp)
以上の実行で保存されるファイルは次の通りです。
保存先を指定したクラスをポリモーフィックに保存/回復するサンプルを示します。保存先をマスター・ファイルと取引ファイルへ分割するケースを使います。できるだけ小さなサンプルにしていますので少し違和感があると思いますが、雰囲気は掴めると思います。
なお、このように基底クラスへのポインタから保存/回復することもできますし、普通にクラス・インスタンスを直接保存/回復することもできます。
保存先の定義 (source/reference_and_test/basic/common.h)
クラス例 (source/reference_and_test/basic2/test_destinations.h)
顧客管理を想定してます。BaseCustomerを基底クラスとし、法人の顧客をCorporateCustomer、個人の顧客をIndividualCustomerで管理する想定です。基底クラスで名前を記録し、派生クラスはそれぞれ、資本金と売掛金残高、誕生日と提供したポイント数を記録します。名前と資本金と誕生日はマスター・ファイル、売掛金とポイント数は取引ファイルへ保存します。
保存ソース:(source/reference_and_test/basic2/test_destinations.cpp)
これにて次のように保存されます。
tutorise_destinationsMaster.json:
誕生日が\
でエスケープされているのは、Jsonの仕様によるものです。
tutorise_destinationsTrade.json:
保存データのまとめ:
クラス | メンバ変数 | 内容 | 保存先 |
---|---|---|---|
CorporateCustomer | mName | "Theoride Technology" | マスター・ファイル |
mCapitalStock | 2,000,000 | マスター・ファイル | |
mTradeAccounts | 500,000 | 取引ファイル | |
IndividualCustomer | mName | "Yossi Tahara" | マスター・ファイル |
mBirthday | 1962/01/01 | マスター・ファイル | |
mPoint | 12,000 | 取引ファイル |
回復ソース:(source/reference_and_test/basic2/test_destinations.cpp)
THEOLIZER_PROCESS(aSerializerMaster, aList);にてマスター・ファイルから回復してます。
THEOLIZER_PROCESS(aSerializerTrade, aList);にて取引ファイルから同じインスタンスへ回復してます。
これにより分割して保存したクラスを合成して回復します。
以上により回復したデータは次のようになります。
回復結果のまとめ:
クラス | メンバ変数 | 内容 |
---|---|---|
CorporateCustomer | mName | "Theoride Technology" |
mCapitalStock | 2,000,000 | |
mTradeAccounts | 500,000 | |
IndividualCustomer | mName | "Yossi Tahara" |
mBirthday | 1962/01/01 | |
mPoint | 12,000 |
クラス・インスタンスをメンバ変数として持つクラスについて、注意点があります。他のクラスを含むクラスを親クラス、他のクラスに含まれるクラスを子クラスとします。
この時、親クラス側で子クラス型のメンバ変数に保存先をAと指定し、子クラスのメンバ変数xに保存先をBとしていた場合、親クラスをBへ保存した時にxが保存されません。これは仕様ですがミスし易い部分です。
以下具体例で説明します。
親クラスをDestinationParent、子クラスをDestinationChildとします。
親クラスはDestinationChild型のmDestinationChildメンバ変数を持っていて、これは保存先としてDestAを指定します。子クラスは2つのメンバ変数mAnnotateAとmAnnotateBを持ち、それぞれ保存先としてDestA、DestBを指定します。
保存先の定義 (source/reference_and_test/basic/common.h)
クラス例 (source/reference_and_test/basic2/test_destinations.h)
保存ソース:(source/reference_and_test/basic2/test_destinations.cpp)
これにて次のように保存されます。
tutorise_destinationsA.json:
mDestinationChildのmAnnotateBはDestBのみ保存なので、tutorise_destinationsA.jsonには保存されません。
tutorise_destinationsB.json:
tutorise_destinationsB.jsonには、指示通りmDestinationChildが含まれません。 上記のどちらにもmDestinationChildのmAnnotateBが保存されないことに注意して下さい。
回復ソース:(source/reference_and_test/basic2/test_destinations.cpp)
以上により回復したデータは次のようになります。mDestinationChild.mAnnotateBが0のままです。 これはミスを誘発し易いですので、子クラスに保存先を指定する際は慎重に行って下さい。
なお、基底クラスには親クラス側に保存先を指定できていため、同様のミスは発生しません。
これは使い方説明で用いたDefaultSaveとDefaultNonSaveの保存/回復を、全てのシリアライザ、全ての書式でテストしています。
source/reference_and_test/basic2/test_destinations.cppでテスト関数を定義してます。
source/reference_and_test/basic2/test_destinations.hでテスト用のクラスを定義してます。
DestinationTestChildクラスとDestinationTestParentクラスを用います。両方ともデフォルト保存型です。
前者はint型、後者はDestinationTestChild型のメンバ変数を下記のように持ちます。
メンバ変数 | 保存先指定 |
---|---|
mNoAnnotate | 保存先指定無し |
mAnnotateA | DestAへ保存 |
mAnnotateB | DestBへ保存 |
mAnnotateAB | DestAとDestBの両方へ保存 |
mAnnotateC | DestCへ保存 |
mAnnotateN | 非保存指定 |
source/reference_and_test/basic2/test_destinations.cppでテスト関数を定義してます。
下記組み合わせでテストしています。
シリアライザ | テストしている関数 |
---|---|
保存先指定無し | saveSpecifySaving()とloadSpecifySaving()内の最後の1つ |
DestAのみ | saveDestinations()の先頭で保存し、loadDestinations()で単独回復 |
DestBのみ | saveDestinations()の2番目で保存し、loadDestinations()で合成回復 |
DestAとDestB | saveDestinations()とloadDestinations()の最後の1つ |
以上により、下記組み合わせのテストを行っています。
シリアライザ | メンバ変数 | 保存先指定されたメンバ変数内のメンバ変数 |
---|---|---|
指定無し | 指定無し | 指定無し(mNoAnnotate) |
単独指定有り | 親と同じ指定有り(mAnnotateA, mAnnotateB) | |
親と一部同じ複数指定有り(mAnnotateAB) | ||
親と異なる指定有り(mAnnotateC) | ||
保存無し指定(mAnnotateN) | ||
複数指定有り | 上記と同じセット | |
保存無し指定 | 上記と同じセット | |
単独指定有り(DestA) | 上記と同じセット | 上記と同じセット |
単独指定有りで合成回復(DestB) | 上記と同じセット | 上記と同じセット |
複数指定(DestA,DestB) | 上記と同じセット | 上記と同じセット |