Как добавить 2-кратный производный класс TCollectionItem в TOwnedCollection?

Я хочу реализовать коллекцию или список, используя TOwnedCollection / TCollectionItem. Мне нужен постоянный список (для загрузки и создания из FileStream) классов с полиморфизмом.

Здесь (частично) мой код до сих пор, но мне не удалось создать производный класс 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;

но я не могу написать / прочитать их, используя FileStream / постоянный список. Мне нужно поместить их в TCollection, но не воссоздавая их.

Как?

1 ответ

Решение

Собственная потоковая передача RTF для RTL TCollection объекты только частично поддерживают полиморфные TCollectionItem классы.

Вы можете добавить полиморфный TCollectionItem возражает против TCollection в коде (во время выполнения, а также во время разработки с помощью пользовательского редактора), если они все происходят из общего базового класса, который передается в TCollection конструктор. И такую ​​коллекцию можно даже сохранить как есть в DFM.

Однако при загрузке DFM при потоковой передаче все элементы коллекции, считанные из DFM, будут использовать все TCollectionItem тип класса вы передаете TCollection конструктор. Таким образом, полиморфные классы не могут быть загружены изначально.

Единственный способ переопределить это поведение - отключить потоковую передачу для коллекции (TCollection свойство быть не published или, по крайней мере, пометить его как stored=false), а затем выполните потоковую передачу элементов коллекции вручную.

Есть ваш основной компонент (или что-то еще TPersistent класс владеет коллекцией) переопределить виртуальный DefineProperties() метод для вызова TFiler.DefineProperty() зарегистрировать пользовательские методы чтения / записи для потоковой передачи элементов коллекции. Чтобы поддерживать полиморфные классы, вам нужно написать каждый элемент ClassName в DFM перед записью значений его свойств, затем прочитайте имя обратно, чтобы вы знали, какой класс создать, прежде чем читать значения свойств.

Другие вопросы по тегам