如何将2次派生类的TCollectionItem添加到TOwnedCollection?

问题描述 投票:0回答:1

我想使用TOwnedCollection / TCollectionItem实现一个集合或列表。我需要一个具有多态性的类的持久列表(从FileStream加载和创建)。

到目前为止,这是我的代码(部分),但是我没有成功创建派生类TGenerator而不是它的父TPowerComponent并将其添加到Collection。

//-------------------------------------------------------------------------------------
class TPCCollection : public TOwnedCollection
    {
            typedef TOwnedCollection inherited;
    private:
            TPowerComponent* __fastcall GetPowerComponent(int Index);
            void __fastcall SetPowerComponent(int Index, TPowerComponent *Value);

    public:
            __fastcall TPCCollection(TPersistent *Owner);

            HIDESBASE TPowerComponent* __fastcall Add(void);
            HIDESBASE TPowerComponent* __fastcall Insert(int Index);

            __property TPowerComponent* PCCollection[int Index] = {read=GetPowerComponent, write=SetPowerComponent};
};

//-------------------------------------------------------------------------------------
class TPowerComponent : public TCollectionItem
{
    typedef TCollectionItem inherited;
public :
    int X, Y, Rotation;
    PowSymbType HisType;

    __fastcall TPowerComponent(TCollection *Collection, PowSymbType AType );
    void __fastcall Assign(TPersistent *Source);
    virtual void __fastcall Paint(TCanvas * Canvas);
};
//-------------------------------------------------------------------------------------
class TGenerator : public TPowerComponent
{
            typedef TPowerComponent inherited;
public :
    double PG, Qgmin, Qgmax, Vsch;

    __fastcall TGenerator(TCollection *Collection, PowSymbType AType );
    void __fastcall Assign(TPersistent *Source);
    virtual void __fastcall Paint(TCanvas * Canvas);    
    };
//-------------------------------------------------------------------------------------
// implementation
//-------------------------------------------------------------------------------------
//  TPCCOllection
//-------------------------------------------------------------------------------------
__fastcall TPCCollection::TPCCollection(TPersistent *Owner)
        : TOwnedCollection(Owner, __classid(TPowerComponent))
{
}
//-------------------------------------------------------------------------------------
TPowerComponent* __fastcall TPCCollection::Add()
{
    return static_cast<TPowerComponent>(inherited::Add());
}
//-------------------------------------------------------------------------------------
TPowerComponent* __fastcall TPCCollection::Insert(int Index)
{
    return static_cast<TPowerComponent>(inherited::Insert(Index));
}
//-------------------------------------------------------------------------------------
TPowerComponent* __fastcall TPCCollection::GetPowerComponent(int Index)
{
    return static_cast<TPowerComponent>(inherited::GetItem(Index));
}
//-------------------------------------------------------------------------------------
void __fastcall TPCCollection::SetPowerComponent(int Index, TPowerComponent *Value)
{
    inherited::SetItem(Index, Value);
}
//-------------------------------------------------------------------------------------
//  TPowerComponent
//-------------------------------------------------------------------------------------
__fastcall TPowerComponent::TPowerComponent(TCollection *Collection, PowSymbType AType )
        : TCollectionItem(Collection)
{
    HisType=AType;
    Rotation=0;
}
//-------------------------------------------------------------------------------------
void __fastcall TPowerComponent::Assign(TPersistent *Source)
{
    TPowerComponent *Src = dynamic_cast<TPowerComponent>(Source);
    if( Src )
        {
                // copy members from Src...
        }
    else    inherited::Assign(Source);
}
//-------------------------------------------------------------------------------------
// se dessine
void __fastcall TPowerComponent::Paint(TCanvas * Canvas)
{
...
}
//-------------------------------------------------------------------------------------
//  TGenerator
//-------------------------------------------------------------------------------------
__fastcall TGenerator::TGenerator(TCollection *Collection, PowSymbType AType )
        :TPowerComponent( Collection, AType )
{
    PG=0; Qgmin=0; Qgmax=0; Vsch=1.0; Con=-1;
}
//-------------------------------------------------------------------------------------
void __fastcall TGenerator::Assign(TPersistent *Source)
{
    TGenerator *Src = dynamic_cast<TGenerator>(Source);
    if( Src )
        {
                // copy members from Src...
        }
    else    inherited::Assign(Source);
}



//-------------------------------------------------------------------------------------
//  Usage 
TPCCollection * NetWork = new TPCCollection(this);

//  Usage to Access all the collection
for( int i=0; i< NetWork->Count; i++)
    {
    ((TPowerComponent*)(NetWork->Items[i]))->Paint(Canvas);
    }

要添加TGenerator而不是TPowerComponent,我使用:

TGenerator * Gen=new TGenerator( NetWork, Generator);

TCollectionItem子项的创建会自动将其自身添加到TCollection中

这里的问题是我们无法将项目创建过程与将其添加到集合中分开。

当我需要另一个可以包含第一个集合列表中某些项目的列表时,例如,SelectedComponents可以拥有一个或一些NetWork Collection的项目,而无需重新创建它们。

这可以通过以下方式完成

std::list<TPowerComponent*> SelectedComponents;

但我无法使用FileStream / persistent list编写/读取它们。我需要将它们放在TCollection中但不重​​新创建它们。

怎么样?

c++builder vcl tcollectionitem townedcollection
1个回答
1
投票

RTL的TCollection对象的原生DFM流仅部分支持多态TCollectionItem类。

您可以在代码中添加多态TCollectionItem对象到TCollection(在运行时,以及在设计时借助自定义编辑器),只要它们都派生自传递给TCollection构造函数的公共基类。这样的集合甚至可以原样保存到DFM中。

但是,当加载DFM时,本机流将强制从DFM读取的所有集合项使用您传递给TCollectionItem构造函数的任何TCollection类类型。因此,无法在本机加载多态类。

覆盖该行为的唯一方法是禁用集合的本地流(使您的TCollection属性为非published,或至少将其标记为stored=false),然后手动流式传输集合项。

让你的主要组件(或任何TPersistent类拥有该集合)覆盖虚拟DefineProperties()方法以调用TFiler.DefineProperty()来注册用于流式传输集合项的自定义读/写方法。要支持多态类,您必须在写入其属性值之前将每个项的ClassName写入DFM,然后再读取该名称,以便在读取属性值之前知道要实例化哪个类。

© www.soinside.com 2019 - 2024. All rights reserved.