【问题标题】:Function Pointers in C++ Class FilesC++ 类文件中的函数指针
【发布时间】:2016-03-04 14:01:07
【问题描述】:

我一直在尝试使用函数指针,但无济于事。我一直在和几个朋友一起创建一个 C++ 11 库,以便更轻松地创建 ASCII 游戏,并且我个人一直在致力于创建一个菜单类。类的牛肉是完整的,但有一个问题 - 我无法获得调用函数的按钮。我总是得到错误:

terminate called after throwing an instance of 'std::bad_function_call'
what():  bad_function_call

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

显然错误存在于指针的某个地方,但我无法终生解决它。提前感谢您的帮助。

菜单.h

#ifndef MENU_H
#define MENU_H

using namespace std;

#include <functional>
#include <string>
#include <map>

class Menu {
    public:
        int numberOfOptions;
        map<int, string> options;
        int currentSelection;
        string title;

        Menu();
        Menu(int initialNumberOfOptions, map<int, string> initialOptions, int initialSelection);
        void display();
        void waitForInput();
        void attachOptionAction(int option, void (*function)());

    private:
        map<int, void (*std::function<void()>)> optionActions;

        void executeOptionAction(int option);
};

#endif

菜单.cpp

#include "Menu.h"
#include <windows.h>
#include <iostream>
#include <conio.h>

Menu::Menu(int initialNumberOfOptions, map<int, string> initialOptions, int initialSelection) {
    title = "";
    numberOfOptions = initialNumberOfOptions;
    options = initialOptions;
    currentSelection = initialSelection;
}

void Menu::display() {
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), {0, 0});
    for(int i = 0; i < 10; i++) {
        cout << "          " << endl;
    }

    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), {0, 0});
    if(title != "") {
        cout << title << endl << endl;  
    }

    for(int i = 0; i < numberOfOptions; i++) {
        if(i == currentSelection - 1) {
            cout << "[ " << options[i] << " ]" << endl;
        } else {
            cout << options[i] << endl;
        }
    }
    waitForInput();
}

void Menu::waitForInput() {
    char input;
    while(!kbhit());
        input = getch();
    if(input == 72 && currentSelection > 1) {
        currentSelection--;
    } else if (input == 80 && currentSelection < numberOfOptions) {
        currentSelection++;
    } else if (input == 13) {
        if(currentSelection == 1) {
            executeOptionAction(1);
        }
        return;
    }

    display();
}

void Menu::attachOptionAction(int option, std::function<void()> function) {
    optionActions[option] = function;
}

void Menu::executeOptionAction(int option) {
    (optionActions[option])();
}

test.cpp

#include "Menu.h"
#include <unistd.h>
#include <iostream>
#include <iomanip>
#include <map>

void test() {
    cout << "Hello, World!";
}

int main() {
    map<int, string> options;
    options[0] = "Play";
    options[1] = "Help";
    options[2] = "Quit";
    Menu menu(3, options, 1);
    menu.title = "ASCII Game Library 2015";
    menu.display();

    void (*actionPointer)() = NULL;
    menu.attachOptionAction(1, (*actionPointer));

    return 0;
}

【问题讨论】:

  • 这不能编译:map&lt;int, void (*std::function&lt;void()&gt;)&gt; optionActions;

标签: class pointers c++11


【解决方案1】:

这是错误的。我什至不确定那应该是什么。

map<int, void (*std::function<void()>)> optionActions;

应该是:

map<int, std::function<void()>> optionActions;

这里也是错误的。如果您没有将 std 导入当前命名空间,那将是正确的。

void attachOptionAction(int option, void (*function)());

应该是:

void attachOptionAction(int option, const std::function<void()> & action);

这里也是错误的。将 std 导入命名空间后,不能将参数命名为 function

void Menu::attachOptionAction(int option, std::function<void()> function)

应该是:

void Menu::attachOptionAction(int option, const std::function<void()> & action)

这里也是错误的。您不检查函数是否存在或是否为其分配了有效的函数指针。你没有。

(optionActions[option])();

应该是:

// Attempt to find the action!
map<int, std::function<void()>>::iterator action = optionActions.find(option);
// Did we find anything?
if (action == optionActions.end())
{
    return;
}
// Is the function assigned to this action valid?
if (action->second)
{
    action->second();
}

您正在将一个空函数指针附加到一个操作并尝试调用它。而且由于没有验证,它就是这样做的。这就是你得到这个异常的原因:

void (*actionPointer)() = NULL;
menu.attachOptionAction(1, (*actionPointer));

但我什至不确定如何编译它:/

编辑:

我希望您能找到这个示例来了解您正在寻找的内容。

#include <map>
#include <string>
#include <cstdlib>
#include <iostream>
#include <functional>

class Menu
{
protected:
    typedef std::function<int (Menu &)> Callback;
    typedef std::map<int, Menu> SubMenus;
public:
    Menu()
        : m_Id(0), m_Name(""), m_Handler(nullptr)
    {

    }

    Menu(int id, const std::string & name, Callback clbk)
        : m_Id(id), m_Name(name), m_Handler(clbk)
    {

    }

    Menu & operator [] (int id)
    {
        return m_Childrens.at(id);
    }

    int Enter()
    {
        int result = 0;

        if (m_Handler)
            result = m_Handler(*this);

        return result;
    }

    void Insert(const Menu & menu)
    {
        m_Childrens[menu.m_Id] = menu;
    }

    void Insert(int id, const std::string & name, Callback clbk)
    {
        m_Childrens[id] = Menu(id, name, clbk);
    }

    void Remove(int id)
    {
        m_Childrens.erase(id);
    }

    int GetId() const
    {
        return m_Id;
    }

    const std::string & GetName() const
    {
        return m_Name;
    }

    const Callback & GetHandler() const
    {
        return m_Handler;
    }

    bool IsChildren(int id) const
    {
        return (m_Childrens.find(id) != m_Childrens.cend());
    }

    Menu & GetChildren(int id)
    {
        return m_Childrens.at(id);
    }

    const SubMenus & GetChildrens() const
    {
        return m_Childrens;
    }
private:
    int         m_Id;
    std::string m_Name;
    Callback    m_Handler;
    SubMenus    m_Childrens;
};

void ClearScreen()
{
    system("cls");
}

int SharedMenuDisplay(const Menu & menu)
{
    ClearScreen();

    std::cout << "Welcome to " << menu.GetName() << std::endl;

    for (const auto & m : menu.GetChildrens())
    {
        std::cout << "> " << m.second.GetId() << " - " << m.second.GetName() << std::endl;
    }

    std::cout << "> 0 - Go Back" << std::endl;

    std::cout << "Please select a sub menu: ";

    int choice;

    std::cin >> choice;

    return choice;
}

int Menu_Home(Menu & menu)
{
    int choice;
    int result = 0;

    do {
        ClearScreen();

        std::cout << "Welcome to " << menu.GetName() << std::endl;

        for (const auto & m : menu.GetChildrens())
        {
            std::cout << "> " << m.second.GetId() << " - " << m.second.GetName() << std::endl;
        }

        std::cout << "> 0 - To Leave" << std::endl;

        std::cout << "Please select a sub menu: ";

        std::cin >> choice;

        if (choice != 0 && menu.IsChildren(choice))
            result = menu.GetChildren(choice).Enter();

    } while (choice != 0);

    return result;
}

int Menu_A(Menu & menu)
{
    int choice;
    int result = 0;

    do {
        choice = SharedMenuDisplay(menu);

        if (choice != 0 && menu.IsChildren(choice))
            result = menu.GetChildren(choice).Enter();

    } while (choice != 0);

    return result;
}

int Menu_A_SubMenu_X(Menu & menu)
{
    ClearScreen();
    std::cout << "You have selected " << menu.GetName() << std::endl;
    std::cout << "> Type something and press Enter to go back..." << std::endl;

    std::string str;
    std::cin >> str;

    return 0;
}

int Menu_A_SubMenu_Y(Menu & menu)
{
    ClearScreen();
    std::cout << "You have selected " << menu.GetName() << std::endl;
    std::cout << "> Type something and press Enter to go back..." << std::endl;

    std::string str;
    std::cin >> str;

    return 0;
}

int Menu_A_SubMenu_Z(Menu & menu)
{
    ClearScreen();
    std::cout << "You have selected " << menu.GetName() << std::endl;
    std::cout << "> Type something and press Enter to go back..." << std::endl;

    std::string str;
    std::cin >> str;

    return 0;
}

int Menu_B(Menu & menu)
{
    int choice;
    int result = 0;

    do {
        choice = SharedMenuDisplay(menu);

        if (choice != 0 && menu.IsChildren(choice))
            result = menu.GetChildren(choice).Enter();

    } while (choice != 0);

    return result;
}

int Menu_B_SubMenu_X(Menu & menu)
{
    ClearScreen();
    std::cout << "You have selected " << menu.GetName() << std::endl;
    std::cout << "> Type something and press Enter to go back..." << std::endl;

    std::string str;
    std::cin >> str;

    return 0;
}

int Menu_B_SubMenu_Y(Menu & menu)
{
    ClearScreen();
    std::cout << "You have selected " << menu.GetName() << std::endl;
    std::cout << "> Type something and press Enter to go back..." << std::endl;

    std::string str;
    std::cin >> str;

    return 0;
}

int Menu_B_SubMenu_Z(Menu & menu)
{
    ClearScreen();
    std::cout << "You have selected " << menu.GetName() << std::endl;
    std::cout << "> Type something and press Enter to go back..." << std::endl;

    std::string str;
    std::cin >> str;

    return 0;
}

int Menu_C(Menu & menu)
{
    ClearScreen();
    std::cout << "You have selected " << menu.GetName() << std::endl;
    std::cout << "> Type something and press Enter to go back..." << std::endl;

    std::string str;
    std::cin >> str;

    return 0;
}

int main(int argc, char **argv)
{
    Menu home(-1, "Home", &Menu_Home);

    home.Insert(1, "Menu Item A", &Menu_A);
    home.Insert(2, "Menu Item B", &Menu_B);
    home.Insert(3, "Menu Item C", &Menu_C);

    home.GetChildren(1).Insert(1, "Sub Menu Item X", &Menu_A_SubMenu_X);
    home.GetChildren(1).Insert(2, "Sub Menu Item Y", &Menu_A_SubMenu_Y);
    home.GetChildren(1).Insert(3, "Sub Menu Item Z", &Menu_A_SubMenu_Z);

    home[2].Insert(1, "Sub Menu Item X", &Menu_B_SubMenu_X);
    home[2].Insert(2, "Sub Menu Item Y", &Menu_B_SubMenu_Y);
    home[2].Insert(3, "Sub Menu Item Z", &Menu_B_SubMenu_Z);

    return home.Enter();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-19
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多