Home > Net >  Create method that accepts method from any child class
Create method that accepts method from any child class

Time:06-23

I apologize for the vague question title, but I'm unfamiliar enough with C to be able to phrase it better.

I'm trying to create a method that takes a method on any child class as one of the parameters, but I'm getting a compiler error that I don't know how to fix. I'd also like to alias the type so it's not so verbose. I'm open to other approaches, but the code I'm working within is more or less setup this way.

Code:

#include <map>
#include <string>

using std::map;
using std::string;

struct ParentClass;
struct DataClass;

using my_handler_type = uint16_t (ParentClass::*)(DataClass&, DataClass&);

struct ParentClass {

    void add_handler(string name, my_handler_type handler) {
        handlers.emplace(name, handler);
    }

private:

    map<string, my_handler_type> handlers;

};

struct ChildClass : ParentClass {
    
private:

    uint16_t some_handling_function(DataClass &, DataClass & );

    void setup_handler() {
        add_handler( "handler_one", &ChildClass::some_handling_function );
    }

};

Error:

example.cpp: In member function ‘void ChildClass::setup_handler()’:
example.cpp:31:37: error: cannot convert ‘uint16_t (ChildClass::*)(DataClass&, DataClass&)’ {aka ‘short unsigned int (ChildClass::*)(DataClass&, DataClass&)’} to ‘my_handler_type’ {aka ‘short unsigned int (ParentClass::*)(DataClass&, DataClass&)’}
   31 |         add_handler( "handler_one", &ChildClass::some_handling_function );
      |                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                     |
      |                                     uint16_t (ChildClass::*)(DataClass&, DataClass&) {aka short unsigned int (ChildClass::*)(DataClass&, DataClass&) example.cpp:14:51: note:   initializing argument 2 of ‘void ParentClass::add_handler(std::string, my_handler_type)’
   14 |     void add_handler(string name, my_handler_type handler) {
      |                                   ~~~~~~~~~~~~~~~~^~~~~~~

CodePudding user response:

You can cast the child class member function pointer to the type of a base class member function pointer.

static_cast<my_handler_type>(&ChildClass::some_handling_function));

So:

#include <iostream>
#include <map>
#include <string>

using std::map;
using std::string;

struct ParentClass;
struct DataClass {};

using my_handler_type = uint16_t (ParentClass::*)(DataClass &, DataClass &);

struct ParentClass {
    void add_handler(string name, my_handler_type handler) {
        handlers.emplace(name, handler);
    }

    void handle(const std::string &ev) {
        if (auto it = handlers.find(ev); it != handlers.end()) {
            DataClass d;
            (this->*it->second)(d, d);
        }
    }

private:
    map<string, my_handler_type> handlers;
};

struct ChildClass : ParentClass {
    uint16_t some_handling_function(DataClass &, DataClass &) {
        std::cout << "handling the stuff\n";
        return 0;
    }

public:
    void setup_handler() {
        // cast the member function pointer here:
        add_handler("handler_one", static_cast<my_handler_type>(
                                       &ChildClass::some_handling_function));
    }
};

int main() {
    ChildClass c;
    c.setup_handler();
    c.handle("handler_one");
}

Demo

CodePudding user response:

The problem is that a pointer to a derived class' member function cannot be implicitly converted to a pointer to a base class' member function. In other words, short unsigned int (ChildClass::*)(DataClass&, DataClass&) cannot be implicitly converted to short unsigned int (ParentClass::*)(DataClass&, DataClass&).

But you can explicitly cast the pointer to derived class' member function to the pointer to the base class' member function using static_cast as done in Ted's answer.

  • Related