Passing a method pointer for a new method to base class - c++

I'd like to be able to call any arbitary method (which are generic methods) defined in a derived class from the base class. The base class doesn't know about them. I'd somehow like to get this pointer and the virtual table offset and be able to call it. Class A doesn't actually need to be the base class, it could be a separete class which doesn't know anything about B but needs to call the methods. Is it possible?
class A
{
public:
typedef void (A::*Method)();
void call(Method p)
{
//...
}
};
class B : public A
{
public:
virtual void meth1()
{
}
virtual void meth2()
{
}
virtual void test()
{
call(&TestTask::meth1);
call(&TestTask::meth2);
}
};
Errors:
test.cpp:420:30: error: no matching function for call to ‘B::call(void (TestTask::*)())’
call(&TestTask::meth1);
^
test.cpp:420:30: note: candidate is:
test.cpp:402:10: note: void A::call(A::Method)
void call(Method p)
^
test.cpp:402:10: note: no known conversion for argument 1 from ‘void (TestTask::*)()’ to ‘A::Method {aka void (A::*)()}’
test.cpp:421:30: error: no matching function for call to ‘B::call(void (TestTask::*)())’
call(&TestTask::meth2);

Non-static member functions need an object to act on, so you can't simply call the member-function pointer by itself. You could define a template to call a member of any class, given an object of that class:
template <class Class>
void call(Class & c, void (C::*method)()) {
(c.*method)();
}
If that's not what you want, then you'll need to clarify what you do want.

You can use the CRTP pattern to accomplish what you are trying.
template <typename T> struct A
{
typedef void (T::*Method)();
void call(Method m)
{
(static_cast<T*>(this)->*m)();
}
};
struct B : A<B>
{
void meth1(){}
void meth2(){}
void test()
{
call(&B::meth1);
call(&B::meth2);
}
};

Related

When using template and inheritance together, I do not know how to override a member function

I have the following code that mixes template and inheritance.
Class Base has some utility function to build items (the work in the sample code), and Child call the work in its implementation of the API call.
In this function
virtual void call() override {
Base<T>::work(); // Problem Here
// work();
}
I try to call work() but got the following error:
test.cc: In member function ‘virtual void Child<T>::call()’:
test.cc:18:2: error: there are no arguments to ‘work’ that depend on a template parameter, so a declaration of ‘work’ must be available [-fpermissive]
So I write Base<T>::work() and makes it work.
Now I have a Grandson class, who want to override the work function. But the override does not work as in Child<T>::call I have explicitly specified calling Base<T>::work(). So what's the correct way to implement Child<T>::call to make the override in Grandson work?
#include <iostream>
template <typename T>
class Base {
protected:
virtual void work() {
T a;
std::cout << "From Base" << '\n';
}
public:
virtual void call() = 0;
};
template <typename T>
class Child : public Base<T> {
public:
virtual void call() override {
Base<T>::work(); // Problem Here
// work();
}
};
template <typename T>
class Grandson : public Child<T> {
protected:
void work() override {
std::cout << "From Grandson" << '\n';
}
};
int main() {
Grandson<int> g;
g.call();
}
Replace Base<T>::work() with this->work().
When you are a template class inheriting from a base class dependent on your template parameter, the compiler doesn't look into your base when it sees something like work(). Instead, you have to tell it that it needs to do that. The easiest way I know of to accomplish that is to prefix the call with this->.
As for why it does not work when you use Base<T>::work(), I am not entirely sure. It's hardcoding it to call the base class implementation, but I'm fairly sure there's a similar syntax that does work.

c++ passing class method as argument to a class method with templates

I'm trying to pass a class method to another class method using template, and cannot find any answer on how to do (no C++11, boost ok):
I simplified the core problem to :
class Numerical_Integrator : public Generic Integrator{
template <class T>
void integrate(void (T::*f)() ){
// f(); //already without calling f() i get error
}
}
class Behavior{
void toto(){};
void evolution(){
Numerical_Integrator my_integrator;
my_integrator->integrate(this->toto};
}
I get as error:
error: no matching function for call to ‘Numerical_Integrator::integrate(<unresolved overloaded function type>)’this->toto);
note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘void (Behavior::*)()’
Thank you.
Bonus: What about with arguments ?
class Numerical_Integrator{
template <class T, class Args>
double integrate(void (T::*f)(), double a, Args arg){
f(a, arg);
}
}
class Behavior{
double toto(double a, Foo foo){ return something to do};
void evolution(){
Foo foo;
Numerical_Integrator my_integrator;
my_integrator->integrate(this->toto, 5, foo};
}
Your question is not really about passing a class method as part of a template parameter.
Your question is really about correctly invoking a class method.
The following non-template equivalent will not work either:
class SomeClass {
public:
void method();
};
class Numerical_Integrator : public Generic Integrator{
void integrate(void (SomeClass::*f)() ){
f();
}
}
A class method is not a function, and it cannot be invoked as a function, by itself. A class method requires a class instance to be invoked, something along the lines of:
class Numerical_Integrator : public Generic Integrator{
void integrate(SomeClass *instance, void (SomeClass::*f)() ){
(instance->*f)();
}
}
You need to revise the design of your templates, and/or class hierarchies in order to resolve this first. Once you correctly implement your class method invocation, implementing a template should not be an issue.

templates and pointers to member functions

I would like to use and work with pointer to some member function and I also want to be able to call that (or other) member function back.
Lets say, I have headers like this:
class A{
public:
template<class T> void Add(bool (T::*func)(), T* member){
((member)->*(func))();
}
};
class B{
public:
bool Bfoo(){return 1;}
void Bfoo2(){
A a;
a.Add(Bfoo, this);
}
};
and cpp like this:
main(){
B f;
f.Bfoo2();
}
I've got following error:
main.h(22) : error C2784: 'void __thiscall A::Add(bool (__thiscall
T::*)(void),T *)' : could not deduce template argument for 'overloaded
function type' from 'overloaded function type'
I need to call A::Add from many classes (and send information about class method and its instance) so that's why I want to use templates
Using Microsoft Visual C++ 6.0. What am I doing wrong? I cannot use boost.
In my opinion, right way to do what you need is to use inheritance, for example:
class A {
virtual void Add() = 0;
}
class B : public A {
void Add() {...}
}
class C : public A {
void Add() {...}
}
So in your main you can do:
A* a = new B();
a->Add(); /* this call B::Add() method */
You need to pass an address of function
a.Add(&B::Bfoo, this);

function pointer to a class member

I am trying to do some like this:
class A {
void *(*func)(void *);
A(void *(*function)(void *)){
func = function;
}
}
class B {
void *real_func(void *);
A ptr;
B()
:ptr(&real_func)
{
...
}
}
But I get this error:
error: ISO C++ forbids taking the address of an unqualified or
parenthesized non-static member function to form a pointer to member
function.
Someone knows how to initialize the function pointer to a function member in the same class???
Thanks!
Carlos
Since real_func is not a static member function, its type cannot be void *(*)(). Instead, it is void *(B::*)() so you need to declare func accordingly:
void *(B::*func)();
// call it like this
pointer_to_b->*func();
If you are careful, you can also use pointer to A as the base class, but you must make sure that the pointer to A points to an instance of B:
void *(A::*func)();
At this point, however, you are mostly just replicating the functionality of virtual member functions. So I would recommend you use that instead:
class A {
virtual void *func() = 0;
};
class B {
void *func() {
// ...
}
};
You could create B like this:
struct B {
static void *real_func(void *);
A ptr;
B()
:ptr(&real_func)
{
...
}
};
A static member function acts like a regular function, so you can create a function pointer for it.
If you don't need a regular function pointer, then you can use std::function:
#include <functional>
struct A {
std::function<void *(void*)> func;
A(std::function<void *(void*)> function)
: func(function)
{
}
};
struct B {
void *real_func(void *);
A ptr;
B()
: ptr(std::bind(&B::real_func,this,std::placeholders::_1))
{
}
};

How to pass a method as callback to another class?

I have a question regarding callbacks using tr1::function. I've defined the following:
class SomeClass {
public:
typedef std::tr1::function<void(unsigned char*, int)> Callback;
void registerCallback(Callback);
private:
Callback callback;
}
I've defined another class:
class SomeOtherClass {
void myCallback(unsigned char*, int);
}
Now I want to register my function 'myCallback' as callback at class 'SomeClass'using the method 'registerCallback'. However, it is not working. I've had a look on the boost documentation on the function and it seems legit to use (member) methods of a class for callbacks. Am I wrong?
Thanks in advance!
Member functions have an implicit first parameter, a this pointer so as to know which object to call the function on. Normally, it's hidden from you, but to bind a member function to std::function, you need to explicitly provide the class type in template parameter.
#include <functional>
#include <iostream>
struct Callback_t {
void myCallback(int)
{
std::cout << "You called me?";
}
};
class SomeClass {
public:
SomeClass() : callback() { }
typedef std::function<void(Callback_t*, int)> Callback;
// ^^^^^^^^^^^
void registerCallback(const Callback& c)
{
callback = c;
}
void callOn(Callback_t* p)
{
callback(p, 42);
}
private:
Callback callback;
};
int main()
{
SomeClass sc;
sc.registerCallback(&Callback_t::myCallback);
Callback_t cb; // we need an instance of Callback_t to call a member on
sc.callOn(&cb);
}
Output: You called me?;
Why all this complicated mumbo-jumbo?
Why not create a class as thus (for example)
Class MouseOverEventCallBack
{
public:
virtual void RunMouseOverCallback() = 0;
};
Then just create classes that inherit this class (and redefine the method RunMouseOverCallback)
Then Register function just needs to be
void registerCallback(MouseOverEventCallBack *callbackObject); // possible could use a reference
The register method will just call the method and the object will have all that it needs.
Seems a bit simpler. Let the compiler do the work with pointers to functions etc.
the function void (*)(unsigned char*, int) is a free function, which is a different type from void (SomeOtherClass::*)(unsigned char*, int), thus the error. You need an object to call the latter, while the former is a free function.
Look at the possible solutions listed in the Boost documentation
Another possibility is that your SomeOtherClass::myCallback is private, so you do not have access to it.
Use templates:
template <class T>
class B
{
public:
typedef void (T::*TCallBackFunction)(void);
void SetCallBack(T* pCallBackClass, TCallBackFunction pCallBackFunction)
{
if(pCallBackFunction && pCallBackClass)
{
m_pCallBackFunction = pCallBackFunction;
m_pCallBackClass = pCallBackClass;
}
}
void StartCallBackFunction()
{
(pCallBackClass->(*m_pCallBackFunction))();
}
private:
TCallBackFunction m_pCallBackFunction;
T* m_pCallBackClass;
};
Such like this. And use it:
...
B<MyClass> b;
b.SetCallBack(&b, &MyClass::MyFunction);
...