简体   繁体   中英

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

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))'

If all you need is beating the error message, then casting will do:

class Derived : public Base
{
    Derived() {
        registerPrepFn( static_cast<PrepFn>(&Derived::derivedPrepFn) );
    };

    void derivedPrepFn( int n ) {};

}

Call it normally with a Base* p ( provided it actually points to a Derived ): (p->*registered)(0)

See http://ideone.com/BB9oy for a working example.

This is not allowed with oop. Behavioural switching is accomplished by polymorphing the object's class at object creation time.

If you need post-object-creation behaviour switching, you might refactor the dynamic behaviour to another set of polymorphic classes and hold a "pointer" to an instance of a class with the correct behaviour. Please Google the "decorated class" software pattern.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM