c++ooppointer-to-member

Why do we need to refer to the object to access a pointer to a member function?


class Harl {
    private:
        void debug( void );
        void info( void );
        void warning( void );
        void error( void );
    public:
        void complain( std::string level );
};
void Harl::complain( std::string level )
{
    int i;
    std::string levels[4];
    void (Harl::*d_ptr)() = &Harl::debug;
    void (Harl::*i_ptr)() = &Harl::info;
    void (Harl::*w_ptr)() = &Harl::warning;
    void (Harl::*e_ptr)() = &Harl::error;

    levels[0] = "DEBUG";
    levels[1] = "INFO";
    levels[2] = "WARNING";
    levels[3] = "ERROR";
    void (Harl::*p_levels[4])();

    p_levels[0] = d_ptr;
    p_levels[1] = i_ptr;
    p_levels[2] = w_ptr;
    p_levels[3] = e_ptr;
    for (i = 0; i < 4; i++) {
        if (level == levels[i])
            break;
    }
    (this->*(p_levels[i]))();
}
int main()
{
    Harl harl1;
    Harl harl2;
    Harl harl3;
    Harl harl4;

    harl4.complain("ERROR");
    harl1.complain("WARNING");
    harl2.complain("DEBUG");
    harl3.complain("INFO");
}

i'm already invoking the function from the object in the main function, and when i need to invoke the member function i need to simply call the function like this :

debug();

but to call the member function from the pointer to member function i need to specify the object using this pointer. why ?

i tried :

*(p_levels[i]))()

I expect the program to know which object I am in because I am invoking the complain function from that object.


Solution

  • I expect the program to know which object I am in because I am invoking the complain function from that object.

    You can think of a pointer to a member function as a pointer to a free function with extra argument. E.g. a pointer to a member function void foo(int) of a class Bar can be considered a free function with the following signature: void foo(Bar*, int).

    The Bar* argument is what this equals to in the body of the function, and, as you can see, it's not bound to the function rigidly, thus you can specify different objects as this first argument and you are not limited to specific context when invoking a member function through a pointer. Thus, the compiler cannot know in advance which this argument you are planning to use in every scenario and requires you to specify it explicitly.

    You are, however, free to bind specific this to such a pointer and use it as a free function later:

    auto boundFoo = std::bind(&Bar::foo, this, std::placeholder::_1);
    
    boundFoo(1); // can now be called as a free function