#массивы #хранилище #cpp
На этот вопрос уже даны ответы здесь: Можно ли хранить объекты разных классов (производных одного абстрактного класса) в одном массиве или списке? (3 ответа) Закрыт 2 года назад. Существует ли возможность в c++ сделать массив из разных типов? Или какое-то хранилище-переменную, в которой можно хранить разнотиповые вещи? У меня есть несколько структур, и массив, который будет динамически изменяться, и вот хотелось бы как-то добавлять в него значения разных типов.
Ответы
Ответ 1
Предложу ещё третий, более с++ способ. Какие разрообразные объекты у Вас не были бы, все равно у них есть общий предок (да, void* - это вырожденный случай и обычно говорит либо о сильной преждевременной оптимизации или просто незнания ООП). Итак, первое - нужно написать базовый класс. От него наследуются другие классы для разных данных. Даже если нужно хранить строку и число. Так как есть базовый класс, то можно написать std::vectorvec; и уже есть массив объектов. Пусть нужно вывести всех их на печать. Для этого для каждого наследника нужно определить метод вида friend ostream& operator<<(ostream& os, const YourType& dt); И все, можно будет выводить на печать таким кодом for (int i = 0; i < vec.size(); i++) std::cout << vec[i] << std::endl; Очень просто. Но пусть нужно сохранять объекты и загружать с файла. Добавим в базовый тип виртуальный метод "getObjectType", "getObjectSize", "saveToStream" и "loadFromStream". Каждый наследник должен будет их определить. Теперь при сохранении где то так fstream fs; fs.write(vec.size(), sizeof(size_type)); for (int i = 0; i < vec.size(); i++) { int t = vec[i].getObjectType(); size_t s = vec[i].getObjectSize(); fs.write(t, sizeof(t)); fs.write(s, sizeof(s)); vec[i].writeToStream(fs); } красиво? А вот с загрузкой немного сложнее. Нужно будет хранить массив соответствий "тип объекта"->"ссылка на конструктор". Но при небольшом кол-ве объектов, можно и if-else или switch size_type c; fs.read(c, sizeof(c)); for (int i = 0; i < c; i++) { int t; size_t s; BaseObj* bb; fs.read(t, sizeof(t)); fs.read(s, sizeof(s)); switch (t) { case 1: bb = new IntObject(); break; case 2: bb = new StringObject(); break; //.... default: // unknown object, can skip fs.seekg (s, fs.beg); break; } bb->loadFromStream(fs, s); } upd Главное не забывать делать методы виртуальными, а также сделать виртуальным деструктор. Конечно, если классы не будут иметь общего предка, то все это работать не будет. Ответ 2
да такое можно сделать, но если вам это понадобилось то скорее всего имеет смысл переделать архитектуру программы. реализовать это можно например в виде велосипеда над указателями Void. или гораздо лучший вариант это использовать boost boost::Any вот тут можно почитать в любом случае, лучше сначала подумать над архитектурой. UPD собственно пример изменения архитектуры привёл KoVadim...
Комментариев нет:
Отправить комментарий