2016-06-13 8 views
-1

私は2つのクラスのWomanとManを持っています。彼らはストリーミングシステムに登録されています。 Womanクラスにはいくつかの属性があり、最も重要なのはManクラスのインスタンスです。 TMemoryStreamクラスとTStringStreamクラスを使用して、私はTumemoryStreamクラスのWriteComponentメソッドとReadComponentメソッドによって、WomanのMan *、Man *のすべての属性を取得できました。実際にはコンパイラは例外をスローし、その理由はMan *がNULLで正しくロードされていないためです。私のプログラムでは、単純なデータ型や他のクラスのインスタンスを含むすべての属性をロードする必要があります。 Man *がNULLではないように、Womanオブジェクトを正しく読み込む方法を教えてください。ここに私のコードスニペットがあります。TMemoryStreamとTStringStreamを使ってオブジェクトの内部オブジェクトを正しく取得する方法

#include <vcl.h> 
#pragma hdrstop 

#include <tchar.h> 
#include <memory> 
#include <iostream> 
#include <conio.h> 
#include <string> 

#pragma argsused 

using namespace std; 

class Man : public TComponent 
{ 
    private: 
    double fMoney; 
    public: 
    __fastcall Man(TComponent* _Owner,double InMoney) 
     : TComponent(_Owner) 
     { 
      fMoney = InMoney; 
     } 
    __published: 
    __property double Money = {read=fMoney, write=fMoney}; 
}; 

class Woman : public TComponent 
{ 
    private: 
    int fAge; 
    UnicodeString fMyName; 
    Man* fManInClass; 
    public: 
    __fastcall Woman(TComponent* _Owner, int InAge, UnicodeString InName) 
     : TComponent(_Owner) 
    { 
     fAge = InAge; 
     fMyName = InName; 
     fManInClass = new Man(this, 0); 
    } 
    __published: 
    __property int Age = {read=fAge, write=fAge}; 
    __property UnicodeString MyName = {read=fMyName, write=fMyName}; 
    __property Man* ManInClass = {read = fManInClass, write = fManInClass}; 
}; 


void RegisterClassesWithStreamingSystem(void) 
{ 

    #pragma startup RegisterClassesWithStreamingSystem 
    Classes::RegisterClass(__classid(Man)); 
    Classes::RegisterClass(__classid(Woman)); 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    Woman* FirstWoman = new Woman(NULL, 25, "Anjelina"); 
    FirstWoman->ManInClass->Money = 2000; 
    UnicodeString as; 
    auto_ptr<TMemoryStream> MStr(new TMemoryStream); 
    auto_ptr<TStringStream> SStr(new TStringStream(as)); 

    MStr->WriteComponent(FirstWoman); 
    MStr->Seek(0, soFromBeginning); 
    ObjectBinaryToText(MStr.get(), SStr.get()); 
    SStr->Seek(0, soFromBeginning); 
    as = SStr->DataString; 

    auto_ptr<TMemoryStream> pms(new TMemoryStream); 
    auto_ptr<TStringStream> pss(new TStringStream(as)); 
    TComponent *pc; 

    ObjectTextToBinary(pss.get(), pms.get()); 
    pms->Seek(0, soFromBeginning); 

    pc = pms->ReadComponent(NULL); 


    Woman* AWoman = dynamic_cast<Woman*>(pc); 

    cout << AWoman->Age << endl; 
    cout << AWoman->MyName.c_str() << endl; 
    cout << AWoman->ManInClass->Money << endl; // AWoman->ManInClass is NULL -> Exception 

    delete FirstWoman; 
    pc->Free(); 
    getch(); 
    return 0; 
} 
+0

「TMemoryStream」と「TStringStream」とは何ですか?これらは標準的なC++クラスではありません。実際に特定のフレームワークを使用していますか? –

+0

はい。 Embarcadero XE1でC++ビルダーとコーディングを使用しています –

+0

少なくとも、[tag:C++ builder]のタグがあります。それ以外の場合、あなたの質問はあまりにも広範です。その特定のフレームワークについてはわかりません(少なくとも、C++コミュニティの大きな部分ではない)。 –

答えて

0

これは私があなたのearlier questionmy answerに記載されている同様の問題に関連している - つまり、あなたのWomanクラスがカスタムパラメータを持つコンストラクタを定義し、呼び出すことはできません、このようなDFMストリーミングシステムとしてされていることそのコンストラクタはDFMストリームからWomanを読み取るときに発生します。あなたのMan*ポインタがNULLの理由です - あなたのコンストラクタはそのポインタを初期化するために呼び出されていません。

DFMが呼び出すことができるということだけコンストラクタシグネチャがあります:

__fastcall <classname>(TComponent* Owner) 

あなたはその署名を変更することはできません。 は、追加のオーバーロードされたコンストラクタを必要に応じて追加のパラメータで定義しますが、上記のコンストラクタはDFMストリーミングに必要です。

は、代わりにこれを試してみてください:

#include <vcl.h> 
#pragma hdrstop 

#include <tchar.h> 
#include <memory> 
#include <iostream> 
#include <conio.h> 
#include <string> 

#pragma argsused 

using namespace std; 

class Man : public TComponent 
{ 
private: 
    double fMoney; 

public: 
    __fastcall Man(TComponent* Owner) 
     : TComponent(Owner) 
    { 
    } 

    __fastcall Man(TComponent* Owner, double InMoney) 
     : TComponent(Owner) 
    { 
     fMoney = InMoney; 
    } 

__published: 
    __property double Money = {read=fMoney, write=fMoney}; 
}; 

class Woman : public TComponent 
{ 
private: 
    int fAge; 
    UnicodeString fMyName; 
    Man* fManInClass; 

    void __fastcall SetManInClass(Man *Value) 
    { 
     fManInClass->Money = Value->Money; 
    } 

public: 
    __fastcall Woman(TComponent* Owner) 
     : TComponent(Owner) 
    { 
     fManInClass = new Man(this); 
     fManInClass->SetSubComponent(true); 
    } 

    __fastcall Woman(TComponent* Owner, int InAge, UnicodeString InName) 
     : TComponent(Owner) 
    { 
     fAge = InAge; 
     fMyName = InName; 
     fManInClass = new Man(this); 
     fManInClass->SetSubComponent(true); 
    } 

__published: 
    __property int Age = {read=fAge, write=fAge}; 
    __property UnicodeString MyName = {read=fMyName, write=fMyName}; 
    __property Man* ManInClass = {read = fManInClass, write = SetManInClass}; 
}; 

void RegisterClassesWithStreamingSystem(void) 
{ 
    Classes::RegisterClass(__classid(Man)); 
    Classes::RegisterClass(__classid(Woman)); 
} 
#pragma startup RegisterClassesWithStreamingSystem 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    auto_ptr<Woman> FirstWoman(new Woman(NULL, 25, L"Anjelina")); 
    FirstWoman->ManInClass->Money = 2000; 

    auto_ptr<TMemoryStream> MStr(new TMemoryStream); 
    auto_ptr<TStringStream> SStr(new TStringStream(L"")); 

    MStr->WriteComponent(FirstWoman); 
    MStr->Position = 0; 
    ObjectBinaryToText(MStr.get(), SStr.get()); 
    SStr->Position = 0; 
    UnicodeString as = SStr->DataString; 

    auto_ptr<TMemoryStream> pms(new TMemoryStream); 
    auto_ptr<TStringStream> pss(new TStringStream(as)); 

    ObjectTextToBinary(pss.get(), pms.get()); 
    pms->Position = 0; 

    auto_ptr<TComponent> pc(pms->ReadComponent(NULL)); 

    Woman* AWoman = static_cast<Woman*>(pc.get());  

    cout << AWoman->Age << endl; 
    cout << AWoman->MyName.c_str() << endl; 
    cout << AWoman->ManInClass->Money << endl; 

    pc.reset(); 
    FirstWoman.reset(); 

    getch(); 
    return 0; 
} 

はまたfManInClass->SetSubComponent()への余分な呼び出しに気づきます。これは、デザイン時にフォームデザイナーのWomanコンポーネントを使用し、オブジェクトインスペクタでそのプロパティとサブプロパティを設定する場合に必要です。 DFMストリーミングシステムは、がセット/クリアする内部csSubComponentフラグも使用します。これは、fManInClassオブジェクトがWomanオブジェクトによって所有され、特別な処理をしているVCLシステムへの信号です。

ManInClassプロパティのセッターメソッドが追加されていることにも注意してください。 WomanManオブジェクトを所有しているため、外部呼び出し者がfManInClass変数の値を変更することを許可しないため、メモリリークと所有権の競合が発生します。公開されたプロパティをDFMストリーム可能にするには(仮想ストリーミングを提供するために仮想のTComponent::DefineProperties()メソッドをオーバーライドしない限り)、getterとsetterの両方が必要ですが、クラスメソッドを使用してその変数。

VCLコンポーネントの書き方については、自分で良い本を得ることを強くお勧めします。

+0

もう一度ありがとうございます。あなたは素晴らしいです。あなたは私に、このレベルで役に立つかもしれないと思う主題とvclコンポーネントの記述のようなものをカバーする良いC++ビルダーブックの名前を教えてください。 –