Меню консольного приложения с классами C ++ - PullRequest
0 голосов
/ 22 марта 2019

Сейчас я работаю над личным проектом на C ++, и мне очень нравится учиться.Я только что узнал некоторые идеи по использованию наследования и виртуальных функций.Я решил создать консольное приложение для отслеживания бюджета!Конечно, я мог бы использовать управляющие операторы и переключатели;Тем не менее, я хотел попытаться решить эту проблему с помощью классов.Вот мой код:

Main.cpp

#include <iostream>
#include "MainMenu.h"
#include "Menu.h"

int main() {

std::cout << "Welcome to BudgetTracker!\n" <<
            "Let's get started!\n\n";

Menu *menu = new MainMenu;
int mainInput;

menu->displayMenu();
std::cin >> mainInput;
menu->input(mainInput);

//Somehow switch my menu to a sub menu
//Add a loop without terminating entirely

}

MainMenu.cpp

#include "MainMenu.h"

MainMenu::MainMenu(){}
MainMenu::~MainMenu(){}


void MainMenu::displayMenu() {
std::cout   <<  "Welcome to the MainMenu! \n" <<
                "Select an option from the following: \n" <<
                "1.....Overall View\n" <<
                "2.....Accounts\n" <<
                "3.....Spending\n" <<
                "4.....Statistics\n" <<
                "5.....Budgeting\n" <<
                "0.....Close Program\n\n";
}

void MainMenu::input(int userInput) {
    m_input = userInput;
    std::cout << "You have entered " << m_input << ".\n\n";
    //some code to enter a different submenu
}

В конце концов, я представляю, как пользователь вводит что-то вроде в то время как в mainMenu -> input 2. Теперь в accountMenu -> input 3 для управления учетными записями.Введите 2-> добавить учетную запись.

Можете ли вы, ребята, помочь мне найти способ реализовать эту идею?Я видел что-то в отношении дизайна комбинированного рисунка;однако я чувствовал, что это не соответствует этой идее.Я ошибся?Это неправильный подход?

Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 22 марта 2019

Для меню я рекомендую использовать таблицы состояний (программное обеспечение, управляемое данными):

// Define short hand for function pointer
typedef void (*Menu_Processing_Function_Ptr)();

struct Menu_Item
{
    unsigned int  number;
    const char *  text;
    Menu_Processing_Function_Ptr p_processing_function;
};

Учитывая приведенную выше структуру пунктов меню, вы можете создать общий механизм , который обрабатывает {любое} меню. Меню будет массивом Menu_Item.

void Menu_Engine(Menu_Item * p_menu, unsigned int item_quantity)
{
  // Display the menu
  for (unsigned int i = 0; i < item_quantity; ++i)
  {
    std::cout << p_menu[i].number
              << ". "
              << p_menu[i].text
              << "\n";
  }
  std::cout << "Enter selection: ";
  unsigned int selection;
  std::cin >> selection;
  for (unsigned int i = 0; i < item_quantity; ++i)
  {
     if (selection == p_menu[i].number)
     {
        // Execute the processing function for the selection.
        (p_menu[i].p_processing_function)();
        break;
     }
  }
  if (i >= item_quantity)
  {
     std::cout << "invalid selection\n";
  }
}

Затем вы можете определить меню как:

//  Forward declarations
void Process_Selection_1();
void Process_Selection_2();
void Process_Selection_3();

Menu_Item first_menu[] = 
{
    {1, "First Selection", Process_Selection_1},
    {2, "Second Selection", Process_Selection_2},
    {3, "Third Selection", Process_Selection_3},
};
static const unsigned int menu_size =
    sizeof(first_menu) / sizeof(first_menu[0]);

Пример использования:

int main()
{
   // Process the menu
   Menu_Engine(&first_menu[0]);

   // Pause.
   std::cout << "Paused. Press ENTER to continue.";
   std::cin.ignore(1000000, '\n');

   return 0;
}

Этот шаблон позволяет изменять меню без необходимости повторного тестирования или изменения кода ( engine ). Добавление выделения или изменение выделения не влияет на двигатель.

Это позволяет помещать меню в постоянную память.

Вам понадобится только один движок для обработки нескольких меню.

Редактировать 1: std :: map
Другая возможность состоит в использовании ассоциативного массива, сопоставляющего номер выбора с атрибутами выбора:

struct Menu_Item_Attributes
{
  const char * text;
  Menu_Processing_Function_Ptr p_processing_function;
};
typedef std::map<unsigned int, Menu_Item_Attributes> Menu_Item_Container;

Ваша обработка ввода будет:

unsigned int selection;
std::cout << "Enter selection: ";
std::cin >> selection;
try
{
   Menu_Item_Attributes attributes = menu.at(selection);
   (attributes.p_processing_function)();
}
catch (std::out_of_range& e)
{
  std::cout << "Invalid selection";
}

Напоминание о том, что std::map не может быть сохранен в постоянной памяти и должен быть инициализирован во время выполнения.

0 голосов
/ 22 марта 2019

Мне кажется, что вам нужен шаблон State: https://en.wikipedia.org/wiki/State_pattern

...