Search code examples
c++11pointer-to-member

How to send a pointer of a method of an object into a function? (Solved)


I'm trying to create a notebook program

cpp file:

#include <string>
#include "Menu.h"

class Notebook
{
    std::vector<std::string> m_notes;
public:
    void addNote()
    {
        std::string text;
        std::getline(std::cin, text);
        m_notes.push_back(text);
    }
    void printNotes()
    {
        int cnt = 0;
        while (true)
        {
            system("cls");
            std::cout << "Press RETURN to quit\n\n";
            std::cout << m_notes[cnt];
            char butt;
            butt = _getch();
            switch (butt)
            {
            case 72:
                if(cnt > 0){ cnt--; }
                break;
            case 80:
                if (cnt < m_notes.size() - 1) { cnt++; }
                break;
            case 13:
                return;
            default:
                break;
            }
        }
    }
};

int main()
{
    Notebook note;
    Menu menu;
    menu.addPar( {"Add note", note.addNote });
}

Menu.h:

#include <iostream> 
#include <vector>
#include <Windows.h>
#include <conio.h>

#ifndef MENU_H
#define MENU_H

void gotoxy(short x, short y)
{
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), COORD{ x,y });
}

struct par
{
    std::string name;
    void (*action)();
    int order = 0;
};

class Menu
{
    std::vector <par> pars;
    int order = 0;

public:
    Menu()
    {

    }

    void addPar(par paragraph)
    {
        pars.push_back(paragraph);
    }

    void callMenu(std::string title)
    {
        int menu = 0;
        char symb = 0;
        while (true)
        {
            std::cout << title << "\n\n";
            for (int i = 0; i < pars.size(); i++)
            {
                std::cout << "  " << pars[i].name << "\n\n";
            }

            switch (symb)
            {
            case 72:
                if (menu > 0)
                {
                    menu--;
                }
                break;

            case 80:
                if (menu < pars.size() - 1)
                {
                    menu++;
                }
                break;
            case 13:
                for (int i = 0; i < pars.size(); i++)
                {
                    if (i == pars[i].order)
                    {
                        system("cls");
                        pars[menu].action();
                        return;
                    }
                }
            }
            gotoxy(1, menu * 2 + 2);
            std::cout << ">";
            symb = _getch();
            system("cls");
        }
    }
};
#endif

I tried the code above and recieved an error:

Error C3867 'Notebook::addNote': nonstandard syntax; use '&' to create pointer to Notebook member

I don't understand why the pointer to note.addNote would get me C3867 :(

P.S Stack Overflow doesn't like as much code so I'm gonna write a bunch of nonsense a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a


Solution

  • Use std::function provided by the standard C++ library for storing and using functions.

    So in Menu.h you should write

    #include <functional>
    // ... CODE
    
    struct par
    {
        std::string name;
        // void (*action)();
        std::function<void()> action;
        int order = 0;
    };
    
    // ... MORE CODE
    

    Now in the main function

    // ... blah blah main code
    
    int main()
    {
        Notebook note;
        Menu menu;
        menu.addPar( {"Add note", [&]{ note.addNote(); } });
    }
    

    You use note.addNote which requires the note variable to be captured as this pointer for the Notebook::addNote method. So you have to explicitly write a lambda expression to do that.

    One may not notice that implicit capture happening there but there are many (a lot of!!!) subtle little things happening in the language ;).....