How to register a derived class member function pointer with a base class

c++, pointer-to-member

Solution

This pattern can be handled with the Curiously Recurring Template Pattern, that is, compile-time polymorphism.

The code below compiles without a cast.

template <class D>
class Base {
    protected:
        typedef void (D::*PrepFn) (int n);
        void registerPrepFn(PrepFn fn) {}
        Base() {};
        Base(PrepFn fn) {
            registerPrepFn(fn);
        }
};

class Derived : public Base<Derived>{
    Derived() {
        registerPrepFn( &Derived::derivedPrepFn);
    }
    void derivedPrepFn( int n) {};
};

class Derived2 : public Base<Derived2> {
    Derived2() : Base(&Derived2::derived2PrepFn) {}
    void derived2PrepFn(int n) {}
};

To my taste, the version with `Derived2` is even better, because you push registration up into the base class. By deleting the default `Base` constructor (can't do that here, would break `Derived`), you can force derived classes to supply a pointer-to-member function with the correct signature.

Problem

As opposed to virtual member functions, I need a solution where a function implemented at each level class derivation can be registered for later call by the base class. ( Not just the most derived implementation) To do this, I was thinking on providing a mechanism for derived classes to register their function with the base class such as during the derived class constructor. I'm having trouble with the member function pointer argument though. I was thinking that Derived is derived from Base, the `this` pointer should be automatically casted. Can this be done close to what I am trying or do I need to use static member functions, `void *`, and `static_cast`? ``` class Base { protected: typedef void (Base::*PrepFn)( int n ); void registerPrepFn( PrepFn fn ) {}; } class Derived : public Base { Derived() { registerPrepFn( &Derived::derivedPrepFn ); }; void derivedPrepFn( int n ) {}; } ``` Compiler error: ``` error: no matching function for call to 'Derived::registerPrepFn(void (Derived::*)(int))' note: candidates are: 'void Base::registerPrepFn(void (Base::*)(int))' ```

Original source