C ++ TStringList AddObject - PullRequest
       9

C ++ TStringList AddObject

0 голосов
/ 09 мая 2018

В C ++ Builder я написал простой класс для хранения числа с плавающей запятой.Затем я попытался использовать AddObject из TStringList.

Увы, компилятор выдает 2 ошибки, указывая на строку с AddObject:

Невозможно преобразовать 'TFloatNum 'to' TObject * '

Несоответствие типов в параметре' AObject '(хотел' TObject * ', получил' TFloatNum ')

Что я делаю не так?

class TFloatNum {
  public:
    float N;
};

void __fastcall TForm1::btnAddClick(TObject *Sender)
{
  TFloatNum G;
  G.N = 75.5;
  StringList1->AddObject("a", G);
}

1 Ответ

0 голосов
/ 10 мая 2018

AddObject() ожидает указатель TObject*, а не экземпляр объекта TFloatNum. TFloatNum не является производным от TObject, и вы все равно даже не сохраняете указатель.

Вам необходимо динамически распределить объект TFloatNum, чтобы правильно его хранить и юридически (1) .

Если вы не извлекаете TFloatNum из TObject, вам нужно будет привести тип к полученному указателю (обратите внимание - это будет работать только на не-ARC платформах - Windows и OSX - поскольку ARC требует фактического TObject экземпляры объектов на основе):

void __fastcall TForm1::btnAddClick(TObject *Sender)
{
  TFloatNum *G = new TFloatNum;
  G->N = 75.5;
  StringList1->AddObject("a", reinterpret_cast<TObject*>(G));
}

Затем, чтобы получить его позже:

TFloatNum *G = reinterpret_cast<TFloatNum*>(StringList1->Objects[SomeIndex]);
...

И не забудьте delete объект объекта, когда вы закончите с его использованием:

delete G;

В качестве альтернативы, выведите TFloatNum из TObject, тогда вам не нужно приведение типа при передаче указателя TFloatNum* на AddObject() (2) :

class TFloatNum : public TObject {
  public:
    float N;
};

void __fastcall TForm1::btnAddClick(TObject *Sender)
{
  TFloatNum *G = new TFloatNum;
  G->N = 75.5;
  StringList1->AddObject("a", G);
}

TFloatNum *G = static_cast<TFloatNum*>(StringList1->Objects[SomeIndex]);
...
delete G;

(1) : размер float составляет 32 бита. Указатель имеет размер 32 или 64 бита, в зависимости от того, компилируете ли вы для 32-битных или 64-битных систем. Вы могли бы воспользоваться этим фактом и поместить объект TFloatNum непосредственно в сам сохраненный указатель TObject* без динамического выделения объекта TFloatNum (это работает только на не-ARC платформах, когда sizeof(TFloatNum) <= sizeof(void*) ):

class TFloatNum {
  public:
    float N;
};

void __fastcall TForm1::btnAddClick(TObject *Sender)
{
  TObject *obj = NULL;

  TFloatNum &G = reinterpret_cast<TFloatNum&>(obj);
  G.N = 75.5;

  StringList1->AddObject("a", obj);
}

TObject *obj = StringList1->Objects[SomeIndex];
TFloatNum &G = reinterpret_cast<TFloatNum&>(obj);
...

(2) : Если вы используете относительно актуальную версию C ++ Builder, TStringList имеет свойство OwnsObjects, которое можно установить на true, чтобы TStringList бесплатные TObject объекты на основе автоматически для вас.


Как уже говорилось, лучшим решением будет не хранить TFloatNum объектов непосредственно в TStringList таким образом для начала. Храните их в более подходящем контейнере C ++, таком как std::vector или std::list. Затем, если по какой-либо причине вам все еще нужен TStringList, вы можете хранить указатели (std::vector) или TFloatNum* указатели (std::list) в TStringList, чтобы помочь вам вернуться к TFloatNum объектам, когда необходимо.

Использование std::vector<TFloatNum>:

class TFloatNum {
  public:
    float N;
};

void __fastcall TForm1::btnAddClick(TObject *Sender)
{
  TFloatNum G;
  G.N = 75.5;
  SomeStdVector.push_back(G);

  StringList1->AddObject("a", reinterpret_cast<TObject*>(SomeStdVector.size()-1));
}

size_t FloatNumIndex = reinterpret_cast<size_t>(StringList1->Objects[SomeIndex]);
TFloatNum &G = SomeStdVector[FloatNumIndex];
...

Использование std::list<TFloatNum>:

class TFloatNum {
  public:
    float N;
};

void __fastcall TForm1::btnAddClick(TObject *Sender)
{
  TFloatNum G;
  G.N = 75.5;
  SomeStdList.push_back(G);

  StringList1->AddObject("a", reinterpret_cast<TObject*>(&SomeStdList.back()));
}

TFloatNum *G = reinterpret_cast<TFloatNum*>(StringList1->Objects[SomeIndex]);
...
...