Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.50/6: Рейтинг темы: голосов - 6, средняя оценка - 4.50
9 / 7 / 2
Регистрация: 02.12.2021
Сообщений: 49

ООП реализация меню с классом его пунктов. Вызов функций посредством метода класса пункта меню

12.04.2022, 19:26. Показов 1238. Ответов 4

Студворк — интернет-сервис помощи студентам
Проходим ООП. В задании, предшествовавшем этому, необходимо было скопировать пример преподавателя классов Пункта меню и Меню. Дальше будет много кода, извиняюсь за это. Вот как они выглядят:
Пункт меню cpp:
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "MenuItem.h"
#include <iostream>
namespace SAYU {
    MenuItem::MenuItem(char* name, MenuItem::Func func) {
        m_item_name = name;
        m_func = func;
    }
    char*MenuItem::getItemName() {
        return m_item_name;
    }
 
    void MenuItem::printItem() const { std::cout << m_item_name; }
 
    bool MenuItem::run() {
        return m_func();
    }
}
Header:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
namespace SAYU {
    class MenuItem {
    public:
        typedef bool(*Func)();
        MenuItem(char*, Func);
        char* getItemName();
        void printItem() const;
        bool run();
    private:
        Func m_func{};
        char* m_item_name;
    };
}


Само меню cpp:
Кликните здесь для просмотра всего текста

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
#include"Menu.h"
#include<iostream>
namespace SAYU {
    Menu::Menu(char* title, MenuItem* items, size_t count) {
        m_count = count;
        m_title = title;
        m_items = items;
    }
    int Menu::getSelect() const { return m_select; }
    bool Menu::isRun() const { return m_running; }
    size_t Menu::getCount() const { return m_count; }
    char* Menu::getTitle() const { return m_title; }
    MenuItem* Menu::getItmes() { return m_items; }
    void Menu::print() const {
        std::cout << getTitle() << std::endl;
        for (int i = 0; i < m_count; i++) {
            std::cout << i + 1 << '.';
            m_items[i].printItem();
            std::cout << std::endl;
        }
        std::cout << "0. Exit" << std::endl;
    }
    bool Menu::runCommand() {
        print();
        std::cout << "\n Select >> ";
        std::cin >> m_select;
        if (m_select == 0) return false;
        return m_items[m_select - 1].run();
    }
}
И к нему header:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include"MenuItem.h"
namespace SAYU {
    class Menu {
    public:
        Menu(char*, MenuItem* ,size_t);
        int getSelect() const;
        bool isRun() const;
        char* getTitle() const;
        size_t getCount() const;
        MenuItem* getItmes();
        void print() const;
        bool runCommand();
    private:
        int m_select{ -1 };
        size_t m_count{};
        char* m_title{};
        bool m_running{};
        MenuItem* m_items{};
    };
}



И вот так выглядит main для демонстрации работы полученных классов:
Кликните здесь для просмотра всего текста

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
#include <iostream>
#include"Menu.h"
 
bool f1() {
    std::cout << "function f1 is running...\n\n";
    return true;
}
 
bool squairing() {
    std::cout << "Please enter your number-->\n";
    int x{};
    std::cin >> x;
    std::cout << "Squairing your number...\n";
    std::cout << x * x << std::endl;
    return true;
}
 
bool f3() {
    std::cout << "function f3 is running...\n\n";
    return true;
}
 
const int items_number = 3;
 
int main()
{
    using namespace SAYU;
 
    MenuItem items[items_number]{
        MenuItem{new char[256]{"First item"}, f1},
        MenuItem{new char[256]{"Second Item"}, squairing},
        MenuItem{new char[256]{"Third Item"}, f3}
    };
    Menu menu(new char[256]{ "My console menu" }, items, items_number);
 
    while (menu.runCommand()) {
    };
    return 0;
}



Функции f1, squaring и f3 это просто заглушки для демонстрации.

Что здесь важно: вызов этих функции реализован с помощью метода run() класса MenuItem. С ним в дальнейшем и будет проблема.

В настоящем задании, необходимо было написать абстрактный класс User и производные от него классы Employee и Client
Вот они:
User:
Кликните здесь для просмотра всего текста

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
#include "User.h"
#include <iostream>
 
namespace SAYU {
    User::User(char* login, char* password, char* name, int age) {
        m_login = login;
        m_password = password;
        m_name = name;
        m_age = age;
    }
    User::User() {}
 
    char* User::getName() { return m_name; }
    void User::setName(char* name) { m_name = name; }
 
    void User::setPassword(char*  password) { m_password = password; }
    char* User::getPassword() { return m_password; }
 
    void User::setLogin(char* login) { m_login = login; }
    char* User::getLogin() { return m_login; }
 
    void User::setAge(int age) { m_age = age; }
    int User::getAge() { return m_age; }
 
    void User::printInfo() {
        std::cout << m_login << std::endl;
        std::cout << m_password << std::endl;
        std::cout << m_name << std::endl;
    }
}
}
Header:
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
#pragma once
 
namespace SAYU {
    class User {
    protected:
        char* m_login{};
        char* m_password{};
        char* m_name{};
        int m_age{};
    public:
        User();
        User(User&);
        virtual void printInfo() = 0;
        virtual void addUser(User& person) = 0;
 
        User(char* login, char* password, char* name, int age);
 
        char* getName();
        void setName(char*);
 
        void setPassword(char*);
        char* getPassword();
 
        void setLogin(char*);
        char* getLogin();
 
        void setAge(int);
        int getAge();
    };
}


Employee:
Кликните здесь для просмотра всего текста

Employee cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "Employee.h"
#include <iostream>
namespace SAYU {
    Employee::Employee(char* login, char* password, char* name, int age, char* post) : User(login, password, name, age) {
        m_post = post;
    }
    char* Employee::getPost() { return m_post; }
    void Employee::setPost(char* post) { m_post = post; }
 
    void Employee::printInfo() {
        std::cout << m_login << std::endl;
        std::cout << m_password << std::endl;
        std::cout << m_name << std::endl;
        std::cout << m_age << std::endl;
    }
}
Employee header:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once
#include "User.h"
namespace SAYU {
    class Employee : public User
    {
    protected:
        char* m_post{};
    public:
        Employee(char*, char*, char*, int, char*);
        Employee() {}
        char* getPost();
        void setPost(char*);
 
        void printInfo();
    };
}


Client:
Кликните здесь для просмотра всего текста

Client cpp:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "Client.h"
#include <iostream>
namespace SAYU {
    Client::Client(char* login, char* password, char* name, int age, char* service) :User(login, password, name, age) {
        m_service = service;
    }
    char* Client::getService() { return m_service; }
    void Client::setService(char* service) { m_service = service; }
 
    void Client::printInfo() {  
        std::cout << m_login << std::endl;
        std::cout << m_password << std::endl;
        std::cout << m_name << std::endl;
        std::cout << m_age << std::endl;
    }
}
Clent header:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "Client.h"
#include <iostream>
namespace SAYU {
    Client::Client(char* login, char* password, char* name, int age, char* service) :User(login, password, name, age) {
        m_service = service;
    }
    char* Client::getService() { return m_service; }
    void Client::setService(char* service) { m_service = service; }
 
    void Client::printInfo() {  
        std::cout << m_login << std::endl;
        std::cout << m_password << std::endl;
        std::cout << m_name << std::endl;
        std::cout << m_age << std::endl;
    }
}


А теперь, самое главное. По заданию необходимо реализовать тестовую логику классов в файле main, чтобы оценить
работоспособность приложени и добавить эту функциональность в меню, в т.ч. необходимо реализовать пункты добавления в память клиентов и работников. Вот здесь и начинаются проблемы, я не понимаю, как это реализовать так, чтобы можно было привязать к функции run() класса MenuItem.
В последний раз я пробовал менять typedef функцию, менял возвращаемые значения и принимаемые аргументы. К сожалению, этот код утрачен, но я в любом случае думаю, что это неправильный подход.
Я совершенно потерялся в решении.

Наверняка же должен быть какой-то способ не создавать кучу функций для отдельного заполнения массива/вектора необходимыми объектами (Отдельно Employee и Client).
Вот например в коде есть строчка virtual void addUser(User& person) = 0;, я добавил её туда после того как где-то прочитал, что таким образом можно затем переопределить эту функцию в каждом классе для заполнения массива объектами соответствующего типа. Верно ли это? В любом случае после этого мысль не идёт, я во всём запутался и не понимаю, в каком направлении двигаться дальше.

Во-первых, где хранить? В динамическом массиве через указатель или с помощью вектора? Важно ли это вообще в данной ситуации?
Во-вторых, как правильно (или хотя бы ближе всего к "правильному") реализовать нужные функции? Можно ли создать нужный метод в классе-родителе в данной ситуации? В поисках решения наткнулся на понятие "интерфейс", но и здесь я спотыкаюсь. Интерфейс же состоит только из виртуальных функции? Тогда нужно ли создавать сначала интерфейс, затем от него наследовать User и уже потом наследников Client и Employee? Однако это для меня не снимет вопрос технической реализации.
В-третьих, как изменятся функции в классе MenuItem? Будет куча перегрузок? Или получится подвязать всё под существующий метод, который возвращает метод bool? Для последнего варианта вообще не вижу возможностей.

Прошу помощи в том, чтобы с этим разобраться. Просто я даже не могу понять, может среди найденной мной информации есть правильная, но мне не хватает знаний и навыков, чтобы их увидеть.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
12.04.2022, 19:26
Ответы с готовыми решениями:

Выделение главного пункта меню и его дочерных пунктов-элементов
Суть: Есть меню: Главная - Видео - Фото - Статьи - Контакты при наведение на ВИДЕО и ФОТО, выпадает меню - и при нажатие на один из...

Вывод дочерних пунктов одного пункта меню в разные модули (с исключением)
Здравствуйте, Уважаемые коллеги. Joomla 2.5.28. Имеется меню - родитель (It-решения) url: it-resheniya В нем есть около 100 дочерних...

Отключить быстрый вызов пунктов меню
Здравствуйте! Кто знает, напишите как решить проблему, буду благодарен. При открывании обычной папки или программы в пункте меню...

4
2393 / 1914 / 763
Регистрация: 27.07.2012
Сообщений: 5,559
12.04.2022, 21:40
Лучший ответ Сообщение было отмечено Eltan как решение

Решение

Цитата Сообщение от Eltan Посмотреть сообщение
я не понимаю, как это реализовать так, чтобы можно было привязать к функции run() класса MenuItem.
В таком исполнении пункта меню особо много не придумаешь. Судя по всему, придётся делать глобальный массив/вектор объектов User и писать отдельные функции для работы с ним. Например:

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
std::vector<User*> users;
 
bool add_emploee() {
    User* u = new Emploee();
    // ...
    users.push_back(u);
    return true;
}
 
bool add_client() {
    User* u = new Client();
    // ...
    users.push_back(u);
    return true;
}
 
int main() {
    MenuItem i1("Add user", add_user);
    MenuItem i2("Add client", add_client);
    MenuItem items[] = { i1, i2 };
    
    Menu menu(/* ... */);
    // ...
}
1
9 / 7 / 2
Регистрация: 02.12.2021
Сообщений: 49
12.04.2022, 22:08  [ТС]
Спасибо за ответ!
К сожалению, по заданию реализация должна быть такая.
Но чисто теоретически, как может пункт меню быть реализован в ООП? Можете направить на какие-то примеры реализации?
0
2393 / 1914 / 763
Регистрация: 27.07.2012
Сообщений: 5,559
12.04.2022, 22:35
Цитата Сообщение от Eltan Посмотреть сообщение
Но чисто теоретически, как может пункт меню быть реализован в ООП?
Ну ваш вариант вполне рабочий. Просто обычный указатель на функцию не очень функционален, как бы забавно не звучало. Больше возможностей есть, например, у std::function<>. Тогда можно передавать и простые указатели на функции, и функциональные объекты, и лямбды.
0
9 / 7 / 2
Регистрация: 02.12.2021
Сообщений: 49
14.04.2022, 10:42  [ТС]
Спасибо, почитаю об этом!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
14.04.2022, 10:42
Помогаю со студенческими работами здесь

Вызов пункта контекстного меню по кнопке
Можно ли вызвать конкретный пункт контекстного меню по кнопке? Поясняю ситуацию. На форме есть присоединённая рамка объекта OLE. ...

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

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

Вызов метода производного класса (ООП, наследование, списки инициализации)
Вопросы в комментариях исходного кода под катом) /// Базовый. class A { protected: int a; public: A(): a(1){} };

MainMenu: поменять цвет и ширину полосы меню и пунктов меню
По форуму конкретного решения не нашел. Не подскажите, возможно ли поменять цвет и ширину полосы меню и пунктов меню в приложении ?


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
Подключение Box2D v3 к SDL3 для Android: физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
Влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru