Search code examples
c++inheritancepointer-to-member

cast a pointer to member function in derived class to a pointer to abstract member function


I'm trying to do something that seems like it should be fairly common but I've been unable to find anyone discussing it. this post on stackoverflow is similar to what I'm trying to do, but not quite the same.

I have an abstract base class:

#ifndef _ABASECLASS_H_
#define _ABASECLASS_H_

using namespace std;

#include <iostream>

#define CALL_MBR_FUNC(object, ptr_to_mem_func) ((object).*(ptr_to_mem_func))

class aBaseClass
{
public:

  typedef void (aBaseClass::*aBaseClass_mem_func)();

  int A;
  int B;

  aBaseClass();

  aBaseClass(int a, int b);

  virtual void function1(aBaseClass_mem_func infunc) = 0; 

  virtual void function2() = 0; 

};

#endif /* _ACLASS_H_ */

and I have a derived class:

#ifndef _ASUBCLASS_H_
#define _ASUBCLASS_H_

using namespace std;

#include <iostream>
#include "aBaseClass.h"


/* A simple class containing two ints and some functions to demonstrate passing via various methods.  It is a subclass of aClass*/
class aSubClass: public aBaseClass
{
public:

  aSubClass();

  aSubClass(int a, int b);

  void function1(aBaseClass_mem_func infunc); 

  void function2(void); 

};

#endif /* _ASUBCLASS_H_ */

where function1 and function2 are:

void aSubClass::function1(aBaseClass_mem_func infunc) 
{
  CALL_MBR_FUNC(*this, infunc)();
}


void aSubClass::function2(void) 
{
  A = 42;
  B = 66;
}

Finally, in the main() I try to call function1 targeted on an object of type aSubClass, passing a pointer to function2 in aSubClass:

int main (int argc, const char * argv[])
{
  aSubClass eh(2,5);
// This doesn't work    
  aBaseClass_mem_func trythis = &aSubClass::function2;
// This also doesn't work
  eh.function1(&aSubClass::function2);

  return(0);
}

OK, we can automatically cast a pointer-to-derived type to a pointer-to-base type. I have now read that we can't pass a pointer-to-derived-member-function to a pointer-to-base-member-function. I think I understand why (the derived member function might make use of things that exist in the derived class but don't exist in the base class).

But I'm trying to build a library of two categories of classes (derived from two base classes). Call them baseclass1 and baseclass2. One of the member functions in any derived class from baseclass1 needs to be able to be handed a particular member function from any derived class from baseclass2. Is there some trick I can use to carry out the necessary cast? Do I have to use the explicit keyword and define the cast somehow?


Solution

  • You could shorten this example a lot:

    struct B {
        virtual void foo() = 0;
    };
    
    struct D : B {
        void foo() override { }
    };
    
    int main() {
        void (B::*ptr)() = &D::foo; // error: cannot initialize a variable of
                                    // type 'void (B::*)()' with an rvalue of type 
                                    // 'void (D::*)()': different classes ('B' vs 'D')
    }
    

    The error message, at least on clang, is pretty clear. gcc just says cannot initialize. The issue is just that you cannot implicitly convert a pointer-to-derived-member to a pointer-to-base-member. But you can do it explicitly with static_cast:

    void (B::*ptr)() = 
        static_cast<void (B::*)()>(&D::foo); // ok!
    

    Side-note: please remove the CALL_MBR_FUNC macro from your code and never write such a thing ever again.