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

How to add a 2-times derived class of TCollectionItem to TOwnedCollection?

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

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

//-------------------------------------------------------------------------------------
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 集合的项目,而无需重新创建它们。

这可以通过

来完成
std::list<TPowerComponent*> SelectedComponents;

但我不能 write/read 他们使用 FileStream / 持久列表。我需要将它们放在 TCollection 中但不重新创建它们。

如何?

TCollection 对象的 RTL 本机 DFM 流仅部分支持多态 TCollectionItem classes.

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

但是,当加载回 DFM 时,本机流式传输将强制从 DFM 读取的所有集合项使用您传递给 TCollection 构造函数的任何 TCollectionItem class 类型。所以,多态的 classes 不能原生加载。

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

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