Передайте указатели на функции-члены по аргументам и сохраните их - PullRequest
0 голосов
/ 24 января 2011

Я пытаюсь заняться ООП небольшим моим проектом.Я пытаюсь создать простой класс Menu (на основе терминала), чтобы создать, показать и выполнить меню.И это меню должно выполнять функции из Календаря второго класса, который является «основной» программой.

Какой интерфейс я пытаюсь получить:

int main()
{
    Menu menu;
    menu.add("Exit program", &Calendar::exit);
    menu.show();
    menu.execute(menu.EXIT); // or just 0
}

Что должно выглядеть примерно так:

КАЛЕНДАРНОЕ МЕНЮ

0 Выход из программы

Чего я хочу добиться - это добавить () - метод должен добавить функцию-указатель на карту,Это где моя проблема начинается.В настоящее время у меня есть жестко запрограммированный массив с указателями на функции в моем методе execute ().Теперь я хочу динамически добавить пункт меню с соответствующей функцией.

class Menu {
    // declaration of function-pointer thingy
    typedef void (Calendar::*CalendarPtr)(); 

    // will hold the string in the add()-method
    std::vector<std::string> options_strings; 
    // will hold the integer associated to the appropriate function
    std::map<int, CalendarPtr> options_map; 
public:
    // possible options
    enum OPTIONS {EXIT}; 
    // shows the menu on-screen
    void show(); 
    // should add string to vector, function-pointer to map
    void add(std::string, CalendarPtr); 
    // should execute appropriate function (based on option passed)
    void execute(OPTIONS option); 
};

// ...

void Menu::add(std::string option, CalendarPtr) // what doesn't work obviously
{
    // adding string to vector
    options_strings.push_back(option);

    // Just binding the latest entry of the string to the function-pointer
    int index = options_strings.size();

    // TRYING to add function-pointer to map
    options_map.insert(std::pair<int, CalendarPtr>(index, CalendarPtr)); 
}

Menu::execute(OPTIONS option) // enum declared as public in class
{
    int option = EXIT; // or 0
    CalendarPtr cptr[] = {&Calendar::exit};
    Calendar* cal;
    if (option >= 0 && option < static_cast<int>(options_strings.size()))
        (cal->*cptr[option])();
}

В настоящее время строка вставки дает:

.. / src / Menu.cpp: 24: ошибка: ожидаемое первичное выражение перед ';'токен

, который означает, что мое использование указателей на функции неверно, но каков правильный путь?Как бы я объявил требуемый метод add () (так, какие параметры), как я бы вставил указатели функций на карту и как я бы вызвал нужный элемент на карте с помощью метода execute () -?

Если что-то не понятно, пожалуйста, скажите это, и я постараюсь объяснить это лучше / иначе:)

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

РЕДАКТИРОВАТЬ 1:

Я изменил

void Menu::add(std::string option, CalendarPtr)
// ...
options_map.insert(std::pair<int, CalendarPtr>(index, CalendarPtr)); 

на

void Menu::add(std::string option, CalendarPtr cptr)
// ...
options_map.insert(std::pair<int, CalendarPtr>(index, cptr)); 

Но как вы «вызываете» функцию во вставленной (скажем, индекс 0) позиции?options_map0;не работает ...

РЕДАКТИРОВАТЬ 2:

Вставлен указатель функции с индексом 1;) Проблема решена!

Я получаю сообщение об ошибке, когда у меня есть этот метод:

void Menu::execute(OPTIONS option)
{
    Calendar c;
    Calendar* calendar = &c;
    CalendarPtr cptr = options_map.at(0);
    (*calendar.*cptr)();
}

прекращение вызова после выброса экземпляра 'std :: out_of_range' what (): map :: at

Итак, я заключаю, что вставка не удалась, почему так?

Ответы [ 3 ]

2 голосов
/ 24 января 2011

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

void Menu::add(std::string option, CalendarPtr ptr) // what doesn't work obviously
{
    // adding string to vector
    options_strings.push_back(option);

    // Just binding the latest entry of the string to the function-pointer
    int index = options_strings.size();

    // TRYING to add function-pointer to map
    options_map.insert(std::pair<int, CalendarPtr>(index, ptr)); 
}

Я бы порекомендовал реализовать делегат (например, Невозможно быстрые делегаты C ++ ) для этого.Вызовы функций через указатели на функции-члены очень медленные, и версия делегата будет намного более элегантной и очень быстрой.

Обновление

Во-первых: вам на самом деле не нужно использовать options_strings, ты знаешь что?Вы можете просто использовать

std::map<std::string, CalendarPtr> options_map; 

для сопоставления строк с указателями на функции-члены.

Обновление 2:

Так что, как только вы восстановите CalendarPtr, вы будете вызывать его следующим образом:

void CallIndex(Calendar* calendar, int index) {
    CalendarPtr pfunc = options_map[index].second;
    (*calendar).*pfunc();
}

Но вы можете захотеть избежать синтаксических ошибок при вызове функции-члена с использованием указателя на функцию-члена .

1 голос
/ 24 января 2011

В Menu::add вы не дали своему аргументу CalendarPtr имя. Это законно, если вы на самом деле не хотите использовать этот аргумент!

0 голосов
/ 24 января 2011

Основная ошибка в том, что вы пытаетесь добавить тип к map вместо объекта. Другие включают - использование непостоянной ссылки на std::string в параметрах, что приводит к ненужному копированию. Используя int для представления размера, его емкости недостаточно, вместо этого вы должны использовать size_t. Вот код, который должен помочь:

#include <map>
#include <vector>
#include <string>

struct Calendar {
    void exit () {}
};

class Menu {
    // declaration of function-pointer thingy
    typedef void (Calendar::*CalendarPtr)(); 

    // will hold the string in the add()-method
    std::vector<std::string> options_strings; 
    // will hold the integer associated to the appropriate function
    std::map<size_t, CalendarPtr> options_map; 

public:
    // possible options
    enum OPTIONS {EXIT}; 

    // shows the menu on-screen
    void show(); 

    // should add string to vector, function-pointer to map
    void add(const std::string &, CalendarPtr); 

    // should execute appropriate function (based on option passed)
    void execute(OPTIONS option); 
};

// ...

void Menu::add (const std::string & option, CalendarPtr v) // what doesn't work obviously
{
    // adding string to vector
    options_strings.push_back (option);

    // Just binding the latest entry of the string to the function-pointer
    size_t index = options_strings.size ();

    // TRYING to add function-pointer to map
    options_map.insert (std::make_pair (index, v)); 
}

void Menu::execute(OPTIONS option) // enum declared as public in class
{
    Calendar c;
    option = EXIT; // or 0
    CalendarPtr cptr[] = {&Calendar::exit};
    Calendar* cal = &c;
    if (option >= 0 && option < static_cast<int>(options_strings.size()))
        (cal->*cptr[option])();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...