Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.59/34: Рейтинг темы: голосов - 34, средняя оценка - 4.59
0 / 0 / 0
Регистрация: 01.11.2017
Сообщений: 13

Хранение объектов разных типов в контейнере

16.07.2020, 17:24. Показов 7232. Ответов 10

Студворк — интернет-сервис помощи студентам
Добрый день. Требуется реализовать контейнер, который хранит объекты разных типов. Есть две мысли.
1. Воспользоваться полиморфизмом. Мы создаем родительский тип Base, а затем создает обертки для стандартных типов (double, float, int, string). К примеру:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Node {
public:
    Node()= default;
    virtual void print_value() = 0;
    /* можно ли как-то возвращать не std::string, а конкретный тип? 
     * допустим тип some_type ? */
    virtual std::string get_value() = 0;
private:
    some_type value;
};
 
/* Float, String, Double имеют такую же структуру*/
class Int : Node {
public:
    explicit Int(int val) : value(val) {}
 
    void print_value() override {
        std::cout << value << std::endl;
    }
 
    std::string get_value() override {
        return std::to_string(value);
    }
 
private:
    int value;
};
И все бы хорошо, но меня смущает, что я вынужден каждый раз возвращать std::string, а не объект определенного типа, хоть это и логично, пожалуй.

2. Реализация шаблонного контейнера.
Тут у меня совсем нет идей, просто есть чувство, что можно как-то сделать с помощью шаблонов, но после получаса раздумий, идей совсем нет.

Ну и вопрос. В случае, если можно возвращать не std::string, а определенное значение, то как определять, что вернуть? Мысли: возвращать void*, но мне кажется, что это плохое решение.
В любом случае, буду рад вашим советам, заранее спасибо.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
16.07.2020, 17:24
Ответы с готовыми решениями:

Хранение в контейнере обьектов разных классов
Здраствуйте. Есть небольшая иерархия классов, в вершине которой стоит абстрактный класс vehicle, а от него наследуеться пару классов....

Объекты разных типов в одном контейнере и c++ 11 auto
Собственно дабы упростить себе жизнь, решил использовать auto но столкнулся с траблом... class TWireObj{ public: TWireObj(auto...

Хранение разных типов
Приветствую всех. Возник вот такой вопрос. У меня есть, например, 3 разных структуры, каждая из которых имеет разные поля: struct one ...

10
 Аватар для Annemesski
2674 / 1336 / 480
Регистрация: 08.11.2016
Сообщений: 3,692
16.07.2020, 17:28
Мой совет: отказаться от идеи создавать контейнер-помойку. Если же идея в том чтобы хранить только фундаментальные типы, то посмотрите в сторону std::variant
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
16.07.2020, 17:29
Laravelk, есть готовый std::variant, и реализация visitor в качестве способа достать точный тип.

Даже если использовать его непосредственно не хотите, можно подсмотреть реализацию.
0
0 / 0 / 0
Регистрация: 01.11.2017
Сообщений: 13
16.07.2020, 17:30  [ТС]
Я бы в жизни такое не стал бы делать, однако таково задание. Увы.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
16.07.2020, 17:33
Цитата Сообщение от Laravelk Посмотреть сообщение
что я вынужден каждый раз возвращать std::string
А это вы не совсем вникли в полиморфизм. При полиморфизме ничего возвращать вот так не надо. Надо производить операции с конкретным типом полиморфно, т.е. с использованием виртуальных функций.
Архитектура меняется, ничего "возвращать" не требуется.

Добавлено через 1 минуту
Цитата Сообщение от Laravelk Посмотреть сообщение
однако таково задание
А задание-то можно увидеть?
0
0 / 0 / 0
Регистрация: 01.11.2017
Сообщений: 13
16.07.2020, 17:40  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
есть готовый std::variant, и реализация visitor в качестве способа достать точный тип.
DrOffset, для меня это, к сожалению, не подходит. У меня произвольное количество типов, поэтому variant - не совсем то, что мне требуется. visit тоже вряд ли получится прикрутить, но я подумаю.

Цитата Сообщение от DrOffset Посмотреть сообщение
А это вы не совсем вникли в полиморфизм. При полиморфизме ничего возвращать вот так не надо. Надо производить операции с конкретным типом полиморфно, т.е. с использованием виртуальных функций.
Архитектура меняется, ничего "возвращать" не требуется.
Насчет полиморфизма. Да, вы правы, но если я захочу получить значение из контейнера? Допустим, я хочу данный интерфейс:
C++ (Qt)
1
2
3
Container<Node> container;
// заполнение нашими наследниками
double x = container.at(0); // если я уверен, что на данной позиции double
Но что-то мне подсказывает, что это полный бред и такое нереализуемо нормальным способом.

Цитата Сообщение от DrOffset Посмотреть сообщение
А задание-то можно увидеть?
Рассказал знакомый из ВШЭ, а я решил потратить вечер на его решение. И заодно посоветоваться с кем-нибудь, потому что не уверен в эффективности своего решения. Но оно звучит примерно так: нужно реализовать контейнер, который может хранить несколько типов: string, double, int, float. Из требований: возможность расширить, добавить поддерживаемые типы.

У меня есть идея насчет того, как реализовать его с помощью наследования. Чувствую, что можно как-то с помощью шаблонов, но не получается.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
16.07.2020, 17:56
Лучший ответ Сообщение было отмечено Laravelk как решение

Решение

Цитата Сообщение от Laravelk Посмотреть сообщение
но если я захочу получить значение из контейнера?
Вы свели задачу к полиморфизму, так зачем пытаетесь вернуть все обратно? Если вам нужно конкретное значение из полиморфного, то вам не нужен полиморфизм.

При нормальном подходе такой контейнер будет целиком интегрирован в предметную область, в которой он используется. И там использование данных сведется к реализации соответствующих виртуальных функций.

Цитата Сообщение от Laravelk Посмотреть сообщение
ля меня это, к сожалению, не подходит. У меня произвольное количество типов, поэтому variant - не совсем то, что мне требуется. visit тоже вряд ли получится прикрутить, но я подумаю.
Это подходит для вас. Потому что если бы оно не подходило, то не подходил бы и полиморфизм. Не делайте поверхностных выводов, разберитесь получше.

Цитата Сообщение от Laravelk Посмотреть сообщение
У меня есть идея насчет того, как реализовать его с помощью наследования.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>
#include <string>
#include <vector>
#include <memory>
 
class NodeVisitor {
public:
    virtual void visit(int) = 0;
    virtual void visit(double) = 0;
    virtual void visit(std::string const &) = 0;
};
 
class Node {
public:
    virtual void operate_with(NodeVisitor &) = 0;   
};
 
class Int : public Node {
public:
    explicit Int(int val) : value(val) {}
 
    void operate_with(NodeVisitor & v) override {
        v.visit(value);
    }
private:
    int value;
};
 
class Double : public Node {
public:
    explicit Double(double val) : value(val) {}
 
    void operate_with(NodeVisitor & v) override {
        v.visit(value);
    }
private:
    double value;
};
 
class String : public Node {
public:
    explicit String(std::string const & val) : value(val) {}
 
    void operate_with(NodeVisitor & v) override {
        v.visit(value);
    }
private:
    std::string value;
};
 
int main()
{
    std::vector<std::unique_ptr<Node>> all;
    
    all.push_back(std::make_unique<Int>(42));
    all.push_back(std::make_unique<Double>(3.14));
    all.push_back(std::make_unique<String>("Hello World!"));
    
    struct PrintValue : NodeVisitor {
        void visit(int v) {
            std::cout << "Int value: " << v << std::endl;
        }
        void visit(double v) {
            std::cout << "Double value: " << v << std::endl;
        }
        void visit(std::string const & v) {
            std::cout << "String value: " << v << std::endl;
        }        
    };
    
    PrintValue printer;
    for(auto & n : all) {
        n->operate_with(printer);
    }
}
2
0 / 0 / 0
Регистрация: 01.11.2017
Сообщений: 13
16.07.2020, 17:58  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Это подходит для вас. Потому что если бы оно не подходило, то не подходил бы и полиморфизм. Не делайте поверхностных выводов, разберитесь получше.
Спасибо большое. Изучу, разберусь)
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
16.07.2020, 18:08
Лучший ответ Сообщение было отмечено Laravelk как решение

Решение

Laravelk,
Тоже самое на std::variant:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <string>
#include <vector>
#include <variant>
 
template <typename ...Values>
class variant_vector {
public:
    using common_value_type = std::variant<Values...>;
    
    variant_vector() = default;
    
    template <typename T>
    void push_back(T const & v) {
        m_container.push_back(v);
    }
    
    auto begin() { return m_container.begin(); }
    auto end() { return m_container.end(); }
    auto begin() const { return m_container.begin(); }
    auto end() const { return m_container.end(); }    
    
private:
    std::vector<common_value_type> m_container;
};
 
int main()
{
    variant_vector<int, double, std::string> all;
    
    all.push_back(42);
    all.push_back(3.14);
    all.push_back("Hello World!");
    
    struct PrintValue {
        void operator()(int v) {
            std::cout << "Int value: " << v << std::endl;
        }
        void operator()(double v) {
            std::cout << "Double value: " << v << std::endl;
        }
        void operator()(std::string const & v) {
            std::cout << "String value: " << v << std::endl;
        }        
    };
    
    PrintValue printer;
    for(auto & n : all) {
        std::visit(printer, n);
    }
}
0
0 / 0 / 0
Регистрация: 01.11.2017
Сообщений: 13
16.07.2020, 18:10  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Тоже самое на std::variant:
Выглядит интересно. Спасибо, и это изучу
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
17.07.2020, 00:18
Есть еще std::any там вообще можно не особо указывать типы в коде но зато эффективность страдает.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
17.07.2020, 00:18
Помогаю со студенческими работами здесь

Хранение разных типов данных под одним указателем
Добрый день. Необходимо по одному указателю хранить структуры разных типов. Для этого для разных типов структур я сделал общую родительскую...

Вызов метода с одним именем у объектов разных типов
Здравствуйте. Подскажите как решить задачу. Есть 3 класса: A, B, C которые не связаны друг с другом и не наследуют от общего класса. В...

Простое создание строки из объектов разных типов данных
Всем доброго времени суток. Создал класс, который (по моему мнению) сделает более удобным создание строк и их передачу в функции,...

Динамическое добавление объектов разных типов
Цель следующая, хочу сделать что-то вроде категорий (лейблы) и подкатегорий(чекбоксы). TStringList* Sections = new TStringList; ...

Хранение данных разных типов
Уважаемые программисты помогите мне понять тему хранение типов данных. 1)например тип int хранит в себе целые числа.область...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru