c++builder - Возможно ли создать массив компонентов с разным типом?


2

Возник вопрос: возможно ли создать массив компонентов разного типа?

Очень часто нужно исполнить одно и то же действие для многих обьектов, например, изменить какое-то свойство:

TButton *a[]={Button1,Button2,Button3};
for (int i=0;i<sizeof(a)/sizeof(a[0]);i++)
   a[i]->Enabled=true;

А что, если компоненты разные, но имеют какое-то одинаковое свойство, которое нужно изменить? Возможно ли такое осущесвить?

Источник
  •  66
  •  3
  • 25 янв 2012 2012-01-25 12:49:19
можно на питоне — 25 янв 20122012-01-25 15:20:46.000000
Советую не просто почитать, но и разобраться в ООП. Тогда будет лучше понятно, как решить ваш вопрос. — 25 янв 20122012-01-25 14:46:03.000000

3 ответа

1

Это возможно, если все объекты будут унаследованы от одного общего класса (интерфейса), имеющего необходимые всему множеству методы модификации. Пример:

#include "vector"

// Абстрактный класс-интерфейс
class IWindow
{
public:
  virtual ~IWindow(){};

  virtual bool SetEnabled(bool enable) = 0;
  virtual int  GetStatus() const = 0;
};

class A: public IWindow
{
  //реализация 
};

class B: public IWindow
{
  //реализация 
};

class C: public B
{
  //Тоже реализация
};

//Набор объектов, в который можно "складывать" унаследованные 
//от IWindow объекты, чтобы их можно было одинаково обрабатывать.
//ВНИМАНИЕ! Контейнер не управляет временем жизни его элементов!
std::vector< IWindow* > cont;
Чтобы отформатировать код, выделите его мышью и нажмите на кнопку 101010 редактора. — 25 янв 20122012-01-25 13:15:03.000000
3

Если у этих компонентов есть один общий базовый класс с нужным свойством, то можно объявить массив, содержащий базовые компоненты, потом присваивать элементам массива ссылки на нужные компоненты и править свойство.

TComponent * a[] = {NULL, NULL, NULL};
TEdit edit1, edit2; TButton button;
a[0] = edit1;
a[1] = button;
a[2] = edit2;
for (int i=0;i<sizeof(a)/sizeof(a[0]);i++)
   a[i]->Enabled=true;
  • 25 янв 2012 2012-01-25 13:01:09
4

Разделим "одинаковые свойства" на две группы.

Первая группа, она в основном встречается в нормальном коде. Одинаковые свойства определены не в каждом компоненте, а в каком то предке. Достаточно найти подходящего предка и задача сильно упрощается. Для TButton смотрим список TObject -> TPersistent -> TComponent -> TControl -> TWinControl -> -TButtonControl -> TButton. Подозреваю, что Вам подойдет TWinControl. То есть, если создать массив с TWinControl, то туда можно добавлять и TButton, TEdit и другие.

Другая группа - это когда свойства хоть и одинаковые, но объявлены просто сами по себе. Тут уже не так просто, есть разные методы (рефлексия, написание классов-оберток).

  • 25 янв 2012 2012-01-25 12:55:35
Если я не ошибаюсь, то конструкция вида x is TMemo будет так выглядеть dynamic_cast<TMemo*>(x). — 25 янв 20122012-01-25 14:11:31.000000
да, можно. Вот только я не помню, clear у них от общего наследника или нет. Но если что, для таких случаев можно написать так if obj[i] is TMemo then TMemo(obj[i]).clear else if obj[i] is TEdit then TEdit(obj[i]).clear else ShowMessage(ups!); // но можно ничего не выводить. этот метод хорош тем, что если будете использовать наследников от этих компонент (например компоненты со скинами), то все будет работать. — 25 янв 20122012-01-25 13:19:19.000000
У вас в распоряжении еще есть средство dynamic_cast<> для спуска по иерархии, например, если требуется найти в массиве TWinControl* экземпляры TButton*. — 25 янв 20122012-01-25 13:13:18.000000
Ну так выберите подходящего наследника. Какое именно свойство вам нужно менять? — 25 янв 20122012-01-25 13:08:04.000000
По-идее, первый вариант подходит, но проблема есть: создавая массив TWinControl, ведь все-равно нужно достать дочерний эллемент, т.к. возникает ошибка «свойство is not a member of TWinControl» — 25 янв 20122012-01-25 13:06:57.000000