EDIT: I am limited to C++03 on this topic.
In the following code, class Impl
derives from Intf
and contains an instance of class Caller
.
Caller
's ctor takes an Intf::
instance and member function pointer; it invokes the latter on the former in Caller::func()
.
Impl
's ctor registers itself and its member function func()
with its contained Caller
instance.
I would like for Impl
to contain multiple Caller
instances and register different member function pointers with each instance so that invoking each contained Caller
instance's ::func()
results in a different Impl
member function being called - can this be done?
The only way I could think to do this is to define multiple pure virtual functions in Intf
, implement them in Impl
and register those overriding functions. But this is not an ideal solution to me: I would like to know if there's a way to register different member function pointers with different instances of a registering class without creating virtual functions in the interface class 1:1 with overriding functions in the implementing class.
I need to exclude the possibility of Caller
taking an Impl
reference and member function; Caller
can only know about Intf
s and not Impl
s.
// main.cpp
#include <iostream>
class Intf
{
public:
virtual void func() = 0;
typedef void (Intf::*funcPtr)();
};
class Caller
{
public:
Caller( Intf& f, Intf::funcPtr func ) : f_( f ), func_( func ) {}
void func() { f_.func(); }
private:
Intf& f_;
Intf::funcPtr func_;
};
class Impl : public Intf
{
public:
Impl()
: c_ ( *this, &Intf::func )
// , c2_( *this, static_cast<Intf::funcPtr>(func2) )
{
}
void callCaller() { c_.func(); };
// void callCaller2() { c2_.func(); };
private:
void func()
{
std::cout << __FUNCTION__ << std::endl;
}
void func2()
{
std::cout << __FUNCTION__ << std::endl;
}
Caller c_;
// Caller c2_;
};
int main( int argc, char* argv[] )
{
Impl i;
i.callCaller();
return 0;
}
An additional question: could someone explain why in Impl
's ctor, it is necessary to qualify the pointer to member function func()
with Intf::
? I.e. why is this correct...
Impl() : c_ ( *this, &Intf::func ) {}
...and why are these not correct...
Impl() : c_ ( *this, &Impl::func ) {}
Impl() : c_ ( *this, &func ) {}
?
The compiler error in the case of the '&Impl::func' version is:
g++ -g main.cpp && ./a.out
main.cpp: In constructor 'Impl::Impl()':
main.cpp:31:31: error: no matching function for call to 'Caller::Caller(Impl&, void (Impl::*)())'
: c_ ( *this, &Impl::func )
^
main.cpp:31:31: note: candidates are:
main.cpp:16:3: note: Caller::Caller(Intf&, Intf::funcPtr)
Caller( Intf& f, Intf::funcPtr func ) : f_( f ), func_( func ) {}
^
main.cpp:16:3: note: no known conversion for argument 2 from 'void (Impl::*)()' to 'Intf::funcPtr {aka void (Intf::*)()}'
main.cpp:12:7: note: Caller::Caller(const Caller&)
class Caller
^
main.cpp:12:7: note: candidate expects 1 argument, 2 provided
The compiler error in the case of the '&func' version is:
>g++ -g main.cpp && ./a.out
main.cpp: In constructor 'Impl::Impl()':
main.cpp:31:20: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say '&Impl::func' [-fpermissive]
: c_ ( *this, &func )
^
main.cpp:31:25: error: no matching function for call to 'Caller::Caller(Impl&, void (Impl::*)())'
: c_ ( *this, &func )
^
main.cpp:31:25: note: candidates are:
main.cpp:16:3: note: Caller::Caller(Intf&, Intf::funcPtr)
Caller( Intf& f, Intf::funcPtr func ) : f_( f ), func_( func ) {}
^
main.cpp:16:3: note: no known conversion for argument 2 from 'void (Impl::*)()' to 'Intf::funcPtr {aka void (Intf::*)()}'
main.cpp:12:7: note: Caller::Caller(const Caller&)
class Caller
^
main.cpp:12:7: note: candidate expects 1 argument, 2 provided
You might use the old way callback:
typedef void (*callback_t)(void*);
an helper function:
template <typename C, void (C::*M)()>
void member_func(void* instance)
{
C* c = static_cast<C*>(instance); // Not typesafe :-/
((*c).*M)();
}
And then
class Caller
{
public:
Caller(Intf& f, callback_t func) : instance(f), func_(func) {}
void func() const { func_(&instance); }
private:
Intf& instance;
callback_t func_;
};
class Impl : public Intf
{
public:
Impl()
: c_ ( *this, &member_func<Intf, &Intf::func> )
, c2_ ( *this, &member_func<Impl, &Impl::func2> )
{
}
// ...
};
Since C++11, you might replace Caller
by std::function<void(void)>
and initialize it by c2_([=](){ this->func2();})
. and call it c2_();