I'm trying to give a method as a callback of another method just like that:
Actions actions;
Button button;
int main()
{
actions = Actions();
button = Button();
button.onClick(actions.doSmthg);
return 0;
}
Here is my Actions:
class Actions {
public:
Actions();
void doSmthg();
};
and here is the Button with my attempt of implementing a callback pattern:
class Button {
public:
Button() {};
void onClick(void (*callbackPtr)());
};
Sadly I got the following error:
error: invalid use of non-static member function ‘void Actions::doSmthg()’
I've check multiple examples that suggest to use std::bind when dealing with callbacks but I'm really not sure how to make it work.
Any idea to implement such a pattern in C++?
Here is a live sandbox https://onlinegdb.com/nL3SIUOaI.
Method 1
You can make use of std::bind and std::function as shown below:
#include <iostream>
#include <functional>
class Actions {
public:
Actions(){}
void doSmthg(){
std::cout<<"do something called"<<std::endl;
}
};
class Button {
public:
Button() {};
void setFunc(std::function<void ()> eventFunction) { fn = eventFunction; }
void onClick(){
std::cout<<"button clicked"<<std::endl;
//call the function on the passed object
fn();
}
private:
std::function<void ()> fn;
};
int main()
{
Actions action;
Button button;
button.setFunc(std::bind(&Actions::doSmthg, action));
button.onClick();
return 0;
}
The output of the above program can be seen here:
button clicked
do something called
Method 2
Here we make the onClick member function to be a member function template.
#include <iostream>
class Actions {
public:
Actions(){}
void doSmthg(){
std::cout<<"do something called"<<std::endl;
}
};
class Button {
public:
Button() {};
template<typename T>
void onClick(void (T::*callbackPtr)(), T obj){
std::cout<<"button clicked"<<std::endl;
//call the function on the passed object
(obj.*callbackPtr)();
}
};
int main()
{
Actions action;
Button button;;
button.onClick<Actions>(&Actions::doSmthg, action);
return 0;
}
The output of the above program can be seen here:
button clicked
do something called
Related
I have the following code, where the execute() method accepts a function as a parameter and executes it. The start() method then calls execute() in order to run method1().
class Test
{
int Test::start(void)
{
execute(&Test::method1);
return 1;
}
void Test::execute(void(Test::*func)(void))
{
(this->*func)();
}
void Test::method1(void)
{
//Do something...
}
}
Now I want to modify this so I achieve the following:
Create a base class called TestRunner and and move the execute() method to it
Have Test inherit from TestRunner, where it can call the execute() method to run its local methods
I am trying the following, but got stuck in how I should specify the method parameter in execute() i.e. what right now I have as TestRunner::*func.
class TestRunner
{
public:
TestRunner()
{
//Do something...
}
protected:
void execute(void(TestRunner::*func)(void))
{
(this->*func)();
}
}
class Test : TestRunner
{
public:
Test() : TestRunner()
{
}
int start()
{
TestRunner::execute(&Test::method1);
return 1;
}
private:
void method1(void)
{
//Do something
}
}
If I compile the code like it is I obviously get these errors:
no matching function for call to 'Test::execute(void (Test::*)())'
and
no known conversion for argument 1 from 'void (Test::)()' to 'void
(TestRunner::)()'
Can anyone guide me in the right direction here or do I need to do something completely different to achieve what I want?
I've used this answer here to come up with a solution: C++ Pointers to Member Functions Inheritance
Create a callback class:
class Callback
{
public:
virtual ~Callback() { }
virtual void doSomething()=0;
};
Extend the callback class to define how a function is executed and use a template:
template<class T>
class BCallback: Callback
{
public:
~BCallback() { }
BCallback(T *obj, void(T::*fn)()): obj_(obj), fn_(fn) { };
void doSomething()
{
(obj_->*fn_)();
}
private:
T *obj_;
void(T::*fn_)();
};
Use a callback object in the base class:
class TestRunner
{
protected:
void execute(Callback *cb)
{
cb->doSomething();
}
};
Run the method from the derived class:
class Test: TestRunner
{
public:
int start()
{
BCallback<Test> cb(this, &Test::method1);
this->execute(&cb);
return 1;
}
private:
void method1(void)
{
//Do something
}
};
You can use a typedef like this:
typedef void(Test::*Callback)(void);
You can then make your executing function take objects of type Callback. It will look like this Test::execute(Callback).
When calling it, use static_cast<>:
Test tester;
tester.execute(static_cast<Callback>(&DerivedTest::someMethod));
Example Test::execute(Callback) implementation:
Test::execute(Callback cb) {
(this->*cb)();
}
This way you can avoid writing whole two new classes (one of them a template, even!) just to do a simple thing. As a bonus, you can use function overloading to get Test::execute for different function signatures.
I am creating a console menu in C++ and I want to give every item in my menu a callback function, so when an item is selected, a different function is called.
So far, I have this code:
#include <iostream>
#include <vector>
using namespace std;
class Core
{
public:
void action1() {}
void action2() {}
//...
};
typedef void (Core::*CoreFunc)();
class Menu
{
struct Option
{
Option(CoreFunc cb) : callback(cb) {}
//some data
CoreFunc callback;
//some more data
};
vector<Option> m_options;
public:
Menu(Core const& core)
{
addOption(core.action1);
}
void addOption(CoreFunc callback)
{
m_options.push_back(Option(callback));
}
void execOptionX(int index)
{
m_options[index].callback();
}
};
int main()
{
Core core;
Menu menu(core);
menu.execOptionX(0);
return 0;
}
Which is giving me this error:
no matching function for call to ‘Menu::addOption(<unresolved overloaded function type>)’
at addOption(core.action1);
and also
must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘((Menu*)this)->Menu::m_options.std::vector<_Tp, _Alloc>::operator[]<Menu::Option, std::allocator<Menu::Option> >(((std::vector<Menu::Option>::size_type)index)).Menu::Option::callback (...)’, e.g. ‘(... ->* ((Menu*)this)->Menu::m_options.std::vector<_Tp, _Alloc>::operator[]<Menu::Option, std::allocator<Menu::Option> >(((std::vector<Menu::Option>::size_type)index)).Menu::Option::callback) (...)’
when I try to call the function.
I have seen many implementation of member function pointer, but they are all used within the same class.
Why am I getting these errors?
What is the correct syntax to get this code to compile/work?
Thank you
You declared CoreFunc as a non-static pointer-to-member-method. So you need to specify a pointer to the desired method, eg:
addOption(&Core::action1);
More importantly, you also need to provide a Core object instance as the this parameter for the callback. You specify the object via the .* operator (if using an object reference) or the ->* operator (if using an object pointer), eg:
void execOptionX(int index)
{
CoreFunc callback = m_options[index].callback;
(SomeCoreObj.*callback)();
}
void execOptionX(int index)
{
CoreFunc callback = m_options[index].callback;
(SomeCoreObjPtr->*callback)();
}
So, you need to change your Menu class to keep track of the Core object that will be passed to the callback (assuming you don't want to pass the Core object as a parameter to execOptionX(), eg:
class Menu
{
struct Option
{
Option(CoreFunc cb) : callback(cb) {}
//some data
CoreFunc callback;
//some more data
};
Core &m_core;
vector<Option> m_options;
public:
Menu(Core &core)
: m_core(core)
{
addOption(&Core::action1);
}
void addOption(CoreFunc callback)
{
m_options.push_back(Option(callback));
}
void execOptionX(int index)
{
CoreFunc callback = m_options[index].callback;
(m_core.*callback)();
}
};
And of course, the Core object has to remain alive for the lifetime of the Menu (which it does in your main() example).
So basically I'm making buttons in a game, and the buttons are a called Button.
The class i want the function from to store is called SoccerLevelsClass. I've tried looking into function pointers, but I'm not sure what's going on though i think it's the correct thing to do.
I want to save the function of SoccerLevelsClass as a member of Button.
Would i do something like this?
//MenuButton.h
#ifndef MenuButton
#define MenuButton
....
class Button
{
public:
Button(void(*SoccerLevelsClass::func)());
void (*SoccerLevelsClass::function)();
....
}
#endif
//MenuButton.cpp
#include <MenuButton.h>
Button::Button(void(*SoccerLevelsClass::func)())
{
function=func; //something like this
}
I know the code is probably way off, but I'd like to know if anybody has any suggestions.
All i really want to know is if it's possible.
Yes, this can be done - either with function pointers like in your example, or with lambdas if you can use C++11.
However, since you want to call a bound function of another class, you would need to pass/store pointer to an instance of that class as well to do that, unless the function is static.
In C++11, this is trivial:
std::function<void(void)> _f;
void apply() {
_f();
}
Bar(void (Foo::* f)()) {
_f = std::bind(f, Foo());
}
In C++03, this is a little tricky. Note in both versions I construct a temporary to call the member function, but I'm not sure whether it is necessary to store an instance of the class.
#include <iostream>
#include <functional>
struct Foo
{
Foo() { }
void stuff() {
std::cout << "hi\n";
}
};
struct Bar
{
void (Foo::* _f)();
void apply() {
(Foo().*_f)();
}
Bar(void (Foo::* f)()) {
_f = f;
}
};
int main()
{
Bar bar(&Foo::stuff);
bar.apply();
}
For what you are trying to do I would use the observer pattern:
class IFootballObserver
{
public:
virtual void OnBallKicked() = 0;
virtual ~IFootballObserver() {}
};
class Fooball
{
public:
Fooball(IFootballObserver& obs)
: mObs(obs)
{
// Call the observer interface at any time like so:
mObs.OnBallKicked();
}
private:
IFootballObserver& mObs;
};
class Button : public IFootballObserver
{
public:
// Football could be passed in/owned by something else
Button() : mFootball(*this) { }
void DoSomething()
{
// Called when foot ball is kicked
}
private:
virtual void OnBallKicked()
{
DoSomething();
}
Fooball mFootball;
};
I find this easier than using function pointers/std::function. Plus you could have a vector of observers and notify many objects of events.
I have a problem now. I am trying to encapsulatie boost::signal and boost::bind into my own Event class.
class MyEvent
{
private:
boost::signal<void ()> Sig;
public:
void Subscribe(.........)
{
Sig.connect(boost:bind(.........);
}
void Raise()
{
Sig();
}
};
I have try to pass function pointer in the Subscribe function's signature and visual studio just gives me tones of errors.
I dont know how to write the signature of Subscribe and What to pass into boost::bind, ideally I will have boost::bind(&MyClass::MyHandler, &MyClassObject) in Subscribe function and will Call it outside like MyEventObject.Subscribe(&MyClass::MyHandler, &MyClass).
Can any people help me fill that two blanks?
You can just make Subscribe a template:
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
class MyEvent
{
private:
boost::signals2::signal<void ()> Sig;
public:
template<class SlotClass>
void Subscribe(void (SlotClass::*func)(), SlotClass *obj)
{
Sig.connect(boost::bind(func, obj));
}
void Raise()
{
Sig();
}
};
struct Test
{
void f()
{}
};
int main()
{
MyEvent myEvent;
Test test;
myEvent.Subscribe(&Test::f, &test); // test must outlive myEvent!
}
Note however that such a wrapper limits its user very much: with original signal he could connect any callable of any kind created in various ways, while with your wrapper he must pass a pointer to member function and a pointer to object.
I have something a little tricky to explain so I'll try my best. I have an InstructionScreen class that displays arrows & blocks of text that explain what each buttons does & etc. So in InstructionScreen I have a stack of member functions each of those functions will create some arrows & text to explain what a different button does.
The InstructionScreen will be subclassed into MenuInstructScreen, OptionsInstructScreen & etc. and in these classes I will create custom functions that will create arrows & text to explain their screens buttons.
The problem is declaring this stack in InstructionScreen because it will contain functions that are part of their subclass. I am thinking I can do this, but I use templates right?
So the problem in a nutshell is how do I declare a stack that will contain member functions of a class that doesn't exist yet?
The problem is a lot easier to understand & see if you look at this simple example:
typedef class InstructionScreen;
typedef class MenuInstructScreen;
template <typename FooClass>
typedef void (FooClass::*MemberFuncPtr)(); // will be typedef void (MenuInstructScreen::*MemberFuncPtr)();
class InstructionScreen
{
public:
InstructionScreen() {}
void runInstructions()
{
while ( !instructionStep.empty() )
{
(this->*instructionStep.top())();
instructionStep.pop();
}
}
protected:
stack <MemberFuncPtr> instructionStep;
};
class MenuInstructScreen : public InstructionScreen
{
public:
MenuInstructScreen()
{
// Set instruction schedule
instructionStep.push( &MenuInstructScreen::step2() );
instructionStep.push( &MenuInstructScreen::step1() );
}
void step1()
{
// create some widgets that point to buttons & widgets that contain text instructions
}
void step2()
{
// create some widgets that point to buttons & widgets that contain text instructions
}
private:
};
class OptionsInstructScreen : public InstructionScreen
{
public:
OptionsInstructScreen()
{
// Set instruction schedule
instructionStep.push( &OptionsInstructScreen::step2() );
instructionStep.push( &OptionsInstructScreen::step1() );
}
void step1()
{
// create some widgets that point to buttons & widgets that contain text instructions
}
void step2()
{
// create some widgets that point to buttons & widgets that contain text instructions
}
private:
};
C++ doesn't allow templated typedefs, but C++11 supports this via Template Aliases. If you don't have C++11 support in your compiler, you could achieve the same by using a functor such as Boost.Function.
typedef boost::function<void()> Func;
Since your typedef is for member functions that take no arguments, you could use the aboce to define a functor that returns void and accepts no arguments. Although it wouldn't be restricted to members of a specific class. You would push items onto your stack in derived classes using something like:
stack.push(boost::bind(&MenuInstructScreen::step2, this));
stack.push(boost::bind(&MenuInstructScreen::step1, this));
Your original example would now look something like this...
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <stack>
class InstructionScreen
{
public:
void runInstructions()
{
while (!instructionStep.empty())
{
boost::function<void()> func = instructionStep.top();
instructionStep.pop();
func();
}
}
protected:
std::stack<boost::function<void()> > instructionStep;
};
class MenuInstructScreen : public InstructionScreen
{
public:
MenuInstructScreen()
{
instructionStep.push(boost::bind(&MenuInstructScreen::step2, this));
instructionStep.push(boost::bind(&MenuInstructScreen::step1, this));
}
void step1()
{
//
}
void step2()
{
//
}
};
class OptionsInstructScreen : public InstructionScreen
{
public:
OptionsInstructScreen()
{
instructionStep.push(boost::bind(&OptionsInstructScreen::step2, this));
instructionStep.push(boost::bind(&OptionsInstructScreen::step1, this));
}
void step1()
{
//
}
void step2()
{
//
}
private:
};
int main() { }
There are no "template typedef"s in C++. In C++0x you can use template aliases, but support for that is limited at the moment.
Why not simply add a virtual function to your base class:
virtual void steps() { };
Then let each derived class implement it:
void steps() { step1(); step2(); }
Then you can store pointers-to-base-class in your stack and just call ->steps().