John
John

Reputation: 11921

C++ Pointer to Non-static Member Function Using Templates

I'm having trouble getting member function pointers to work (I don't know whether what I'm trying to do is possible). I want to set a member variable (which is a pointer to a non-static function in another class) and then call that function. I then want to be able to set it to another member function in a different derived class and call that. The 2 derived classes are created by templates, as per below. Can I achieve this and if so, what am I doing wrong?

// Forward declare these, their implementation is irrelevant to the question 
class A;
class B;

// declare a base class that contains a function log() that we want to call
class BaseClass {
   public:
      BaseClass() {}
      virtual ~BaseClass() {}

      virtual void log() {}  // want to call this via function pointers
};

//Using a template means we don't have to specify the type in the vector  
template<class T>
class TemplateVectorOfBaseClass : public BaseClass {
   protected:
      std::vector<T> peripherals;      
}

//  this specific implementation does stuff using Class A
template <int randomTemplateParameter>
class DerivedTemplateClassThatDoesStuffWithAs : public BaseClass
    public:
       DerivedTemplateClassThatDoesStuffWithAs() : TemplateVectorOfBaseClass<A>() {}
       void log() {do_something_here_involving_As();}
       int i[randomTemplateParameter];
};

//  this specific implementation does stuff using Class B
template <int randomTemplateParameter>
class DerivedTemplateClassThatDoesStuffWithBs : public BaseClass
    public:
       DerivedTemplateClassThatDoesStuffWithBs() : TemplateVectorOfBaseClass<B>() {}
       void log() {do_something_here_involving_Bs();}
       float f[randomTemplateParameter];  
};

// Class that contains both templates as member variables    
class ContainerClass {
   public:
      ContainerClass();

      DerivedTemplateClassThatDoesStuffWithAs dtca<5>;
      DerivedTemplateClassThatDoesStuffWithBs dtcb<10>;

      void (BaseClass::*log)();  // pointer to member function log()
    }

// usage
ContainerClass cc;

cc.container.log = &dtca.log;
cc.*log(); // should call vectorContainingAs.log()

cc.container.log = &dtcb.log;
cc.*log(); // should call vectorContainingBs.log()

Upvotes: 0

Views: 901

Answers (1)

Holt
Holt

Reputation: 37706

I can't really rely on your code because it's full of mistakes, so here it's how it should work with a simplified version:

class A { } ;
class B { } ;    

class BaseClass {
public:
    virtual void log () {
        std::cout << "Log BaseClass." << std::endl ;
    }
};

template <class T>
class TVector : public BaseClass { } ;

template <int N>
class DTCA : public TVector <A> { 
public:
    virtual void log () { 
        std::cout << "Log DTCA." << std::endl ;
    }
} ;

template <int N>
class DTCB : public TVector <B> { 
public:
    virtual void log () {
        std::cout << "Log DTCB." << std::endl ;
    }
} ;

class Container {
public:
    DTCA <5> dtca ;
    DTDB <10> dtcb ;
    void (BaseClass::*log) () ;
} ;

I assume the mistakes in the previous part was due to bad copy/paste. The part where you were mainly wrong was the way of assigning the method to the pointer, and the way to call the method on an object:

int main () {
    Container cc ;
    cc.log = &BaseClass::log ; // Store the log member function into cc.log

    (cc.dtca.*cc.log) () ; // Call it on dtca
    (cc.dtcb.*cc.log) () ; // Call it on dtcb

    return 0 ;
}

Output:

Log DTCA.

Log DTCB.

You can not take the address of a method from an instance, you will get something like:

ISO C++ forbids taking the address of a bound member function to form a pointer to member function.

So you take the address to the method, since the type of your variable is (BaseClass::*)() you need to take it directly from the BaseClass. Then, you need to call it using an instance of BaseClass or a derived class.

Upvotes: 1

Related Questions