Создание массива классов C++. Как реализовать? [требует правки]

419
19 марта 2017, 06:13

Допустим есть у меня классы Text, Entry, Label, как мне создать массив экземпляров, данных(имеется ввиду этих) классов. Вообще такое реально. Помогите чем можете.

Answer 1

Массив просто объектов разных классов сделать невозможно. Так как массив в Си++ может содержать объекты только одного типа. В Си++ нет общего класса от котороо все остальные наследуются. Поэтому решением проблемы должно быть "выражение" ваших объектов в виде одного какого-то типа данных.

Первое решение, с применением RTTI:

 void * items[];  //  массив безтиповых указателей,
                  //  либо указателей на общий базовый класс
 for(size_t i = 0; i < count; ++i)
 {
    auto item = items[i];
    if(typeid(Text) == typeid(item))
    {
        auto text = dynamic_cast<Text *>(item);
        // работает с текстом
    }
    else if(typeid(Entry) == typeid(item))
    {
    }
    else if(typeid(Label) == typeid(item))
    {
    }
    else
    {
       // ошибка
    }             
 }

Либо, если указатели не устраивают, можно, аналогичным способом, использовать boost::any.

Второе решение, с применением boost::variant. boost::variant работает как объединение, но для сложных типов. Отличие от указателей в том, что объекты хранятся непосредственно в массиве.

Answer 2

Если Text, Entry, Label не имеют общего предка, но очень хочется держать их в одном массиве, то можно через Type Erasure: допустим, у нас есть

struct Text
{
      string myName() const {return "Text";}
};
struct Entry
{
      string myName() const {return "Entry";}
};
struct Label
{
      string myName() const {return "Label";}
};

и нам хочется иметь вектор или массив с объектами наших структур, по которому мы можем пройтись и запросить myName:

  Elem vec[] {Label(), Text(), Entry(), Text()}; //можно vector<Elem> vec;
  for(const auto& e: vec)
  {
        cout << e.myName() << '\n';
  }

Elem будет выглядеть так:

struct Elem
{
      //поместим объект нашей структуры в указатель на обертку
      //и сотрем его тип, присвоив указателю на базу обертки (см. ниже base и inner)
      template <class MyClass>
      Elem(const MyClass& v): ptr_(new inner<MyClass>(v)) {} 
      Elem(const Elem& e): ptr_(e.ptr_->clone()) {}
      string myName() const {return ptr_->myName();}
private:
      //у наших структур нет общего предка, сделаем его для обертки (inner), а в обертку поместим структуры
      struct base 
      {
            virtual base* clone() const = 0;
            virtual string myName() const = 0;
      };
      //это обертка вокруг наших структур
      template <class MyClass>
      struct inner: base
      {
            inner(const MyClass& v): v_(v) {}
            base* clone() const {return new inner(v_);}
            string myName() const override {return v_.myName();}
            MyClass v_;
      };
private:
      unique_ptr<base> ptr_;
};

Оптимизированную и более жизненную реализацию можно посмотреть здесь.

READ ALSO
Как изменить размер шрифта в NOTIFYICONDATA.szInfo?

Как изменить размер шрифта в NOTIFYICONDATA.szInfo?

Заметил, что у Скайпа например, отличается всплывающее меню в области уведомлений от других приложений в трее - и шрифт, и даже разметкаМне...

299
Оператор switch, нужен ли break после метки default?

Оператор switch, нужен ли break после метки default?

Какой смысл в операторе break после метки default, если оператор switch после default итак завершает свою работу?

292
как переписать класс C# на C++/cli [требует правки]

как переписать класс C# на C++/cli [требует правки]

помогите пожалуйста перевести код

245
c++ снифер не видит GET запросы

c++ снифер не видит GET запросы

Скачал где-то пример снифераОн базируется на ioctlsocket( s, SIO_RCVALL, & flag ) Вопрос, почему снифер не ловит GET запросы, а ловит лишь ответы? Может ли он ловить...

256