Bind Memeber function to another member - c++

I want a system where an object inside a class can call a function inside that class when assigned.
like this collider component example:
class colliderComponent
{
void Collide()
{
//call the assigned function
}
}
class object
{
public:
void collideDelegate()
{
// do something
}
public:
collidercomponent* cc;
Object()
{
cc-> //assign collide delegate to be called on Collide()
}
}

You can do this using std::function and std::bind.
Here is an example (live demo):
#include <functional>
#include <iostream>
class colliderComponent
{
public:
void Collide()
{
collideDelegate();
}
std::function<void()> collideDelegate;
};
class Object
{
public:
void collideDelegate()
{
std::cout << "collide delgate" << std::endl;
}
public:
colliderComponent* cc;
Object(colliderComponent* cc) : cc(cc)
{
cc->collideDelegate = std::bind(&Object::collideDelegate,this); //assign collide delegate to be called on Collide()
}
};
int main()
{
colliderComponent cc;
Object o(&cc);
cc.Collide();
}

Related

Is it possible to replace member function to a noop function?

I write c++ with c++11 and have a question as title.
Ex.
class Hi {
public:
Hi(){};
test() {cout << "test" << endl;};
}
void noop(){
; // noop
};
int main(){
Hi hi();
hi.test = noop; // just example, not real case
return 0;
}
Is that possible to replace test() of class Hi to a noop function in runtime!? Thanks.
You can't replace any function at runtime, whether class member or not.
However, you can achieve the desired effect by using a variable.
(This is yet another example of the "add a level of indirection" method of solving problems.)
Example:
class Hi {
public:
Hi(): test([this]() { do_test(); }) {}
std::function<void()> test;
void do_test() { cout << "test" << endl; }
};
void noop(){}
int main(){
Hi hi;
hi.test(); // Outputs 'test'
hi.test = noop;
hi.test(); // Does nothing
}
You have to think object oriented. In this case you have to elevate your function to be an object we can name it MethodClass then your function in the class Hi will be a pointer to that class. Below a simple example
#include <memory>
class BaseMethodClass
{
public:
virtual void method() = 0;
};
class MethodClass1 : public BaseMethodClass
{
public:
virtual void method()
{
// your implementation here
}
};
class MethodClass2 : public BaseMethodClass
{
public:
virtual void method()
{
// your implementation here
}
};
class Hi
{
public:
Hi() { method = nullptr; };
void setMethod(BaseMethodClass* m) { method.reset(m); }
void test() { if (method) method->method(); };
private:
std::shared_ptr<BaseMethodClass> method;
};
int main()
{
Hi hi;
hi.setMethod(new MethodClass1());
hi.test();
hi.setMethod(new MethodClass2());
hi.test();
return 0;
}
This way you can override your methos as you want not just noop

pass function to class as parameter C++

there is error here(but when i try to send non //class function its workin);
like when i try to add normal void zad1(){somethin...} its works but when i try to add function from class its not :?
//Class that send function//
class Lekcja1 : public ZadanieW {
private:
int numerZad;
public:
Lekcja1(int num) {
this->numerZad = num;
};
~Lekcja1() {};
void tab();
virtual void LekcjaChose();
};
/*void Zad12() {
cout << "dupa" << endl;
}*/
void Lekcja1::tab() {
cout << "dupa" << endl;
};
void Lekcja1::LekcjaChose() {
wyborZadania* obj = new wyborZadania(numerZad,tab);//there is a problem
delete obj;
}
//Class that takin function//
class ZadanieW {
public:
virtual void LekcjaChose() = 0;
};
class wyborZadania{
public:
int _chose;
public:
wyborZadania(int num,void (*tab)()) {
this->_chose = num;
switch (_chose)
{
case 1:
(*tab)();
break;
default:
break;
}
}
~wyborZadania() {}
};
tab is a method of Lekcja1, which is different from a regular function because it needs access to all the data members of Lekcja1.
You can either make Lekcja1::tab a static method, which hides access to data member and makes it a normal function:
class Lekcja1 : public ZadanieW {
//...
public:
static void tab();
//...
};
Or if you need tab to access data members of Lekcja1, then the wyborZadania constructor should take a pointer-to-member of Lekcja1 and an instance of Lekcja1, instead of a function pointer:
wyborZadania(int num,void (Lekcja1::*tab)(), Lekcja1& instance) {
// ...
(instance.*tab)();
// ...
}
If you need that to be more flexible or accept different kinds of classes, then wyborZadania should take an std::function, which is a rich wrapper around a function that will let you bind arguments and data.
wyborZadania(int num,std::function<void()> tab) {
// ...
tab();
// ...
}
And then in LekcjaChose() pass a lambda to call tab():
wyborZadania* obj = new wyborZadania(numerZad,[this](){ tab(); };
demo: https://godbolt.org/z/XfwpSJ
Pointer to member functions are passed differently. You need to pass it like this:
template<class T>
wyborZadania(int num,void (T::*&tab)()) {
this->_chose = num;
switch (_chose)
{
case 1:
(*tab)();
break;
default:
break;
}
}
For this to work Lekcja1::tab() should be declared static, otherwise you also have to pass an object, too. See the live example.
a non-static method cannot be sent as an argument without specifying the object of the class.
Below code uses std::function() to acheive this in simple code.
#include <iostream>
using namespace std;
#include <functional>
//class wyborZadania;
//Class that takin function//
class ZadanieW {
public:
virtual void LekcjaChose() = 0;
};
//Class that send function//
class Lekcja1 : public ZadanieW {
private:
int numerZad;
public:
Lekcja1(int num) {
this->numerZad = num;
};
~Lekcja1() {};
void tab();
virtual void LekcjaChose();
};
void Zad12() {
cout << "dupa" << endl;
}
class wyborZadania {
public:
int _chose;
private:
wyborZadania() {};
public:
wyborZadania(int num, std::function<void()> tab) {
this->_chose = num;
switch (_chose)
{
case 1:
tab();
break;
default:
break;
}
}
~wyborZadania() {}
};
void Lekcja1::tab() {
cout << "dupa1" << endl;
};
void Lekcja1::LekcjaChose() {
wyborZadania* obj = new wyborZadania(numerZad, std::bind(&Lekcja1::tab, this));//there is a problem
//wyborZadania* obj = new wyborZadania(numerZad, Zad12);//there is a problem
delete obj;
}
int main()
{
Lekcja1 obj(1);
obj.LekcjaChose();
}

How to pass a member function as a parameter and execute list of methods on derived object

I want to create an array mapping integer values to member functions so that
(this->*actionMap[i])();
executes the method. In order to populate the array, I would like a method that sets elements of the array to the corresponding action.
I saw in an earlier question that it should use std::function and std::bind but I am not following the syntax, and I do not understand how to declare the array: How to properly pass member function as a parameter
Here is the M(non)WE
Note that I want a base class to be able to execute methods on the derived object.
#include <iostream>
using namespace std;
class Base;
typedef void (Base::*Action)();
class Base {
Action actions[3];
public:
void setAction(int a, Action act) {
actions[a] = act;
}
void f() { cout << "f"; }
void go() {
for (int i = 0; i < 3; i++)
(this->*actions[i])();
}
};
struct Derived : public Base {
void g() { cout << "g"; }
void h() { cout << "h"; }
Derived() {
setAction(1, f);
setAction(2, g);
setAction(1, h);
}
};
int main() {
Derived d;
d.go();
}
execute methods on the derived object.
So you have to have a handle to derived object when you execute the methods. And two of the methods are not in Base::, because they are not inside Base. They are inside Derived, so the pointers could be Derived::*, but that would make no sense and break the model I guess you want to have. I guess you could make your methods g h and f virtual inside Base. But that would again, defeat the purpose, I guess of an observer-like-ish pattern.
What you want to do, is basically easily solved with proper abstraction - std::function and std::bind.
#include <iostream>
#include <array>
#include <functional>
class Base {
std::array<std::function<void()>, 3> actions;
public:
void setAction(int a, std::function<void()> act) {
actions.at(a) = act;
}
void f() { std::cout << "f"; }
void go() {
for (auto&& action : actions) {
if (action) {
action();
}
}
}
};
struct Derived : public Base {
void g() { std::cout << "g"; }
void h() { std::cout << "h"; }
Derived() {
setAction(1, std::bind(&Derived::f, this));
setAction(2, std::bind(&Derived::g, this));
setAction(1, std::bind(&Derived::h, this));
}
};
int main() {
Derived d;
d.go();
}

Threading and Polymorphism

#include<iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <functional>
using namespace std;
class base
{
public:
virtual void fun_1() { cout << "base-1\n"; }
virtual void fun_2() { cout << "base-2\n"; }
};
class derived : public base
{
public:
void fun_1() { cout << "derived-1\n"; }
void fun_2() { cout << "derived-2\n";
}
};
class caller
{
private:
base *p;
derived obj1;
p = &obj1;
public:
void me()
{
std::thread t(std::bind(&base::fun_2, p), this);
t.join();
}
};
int main()
{
caller c;
c.me();
return 0;
}
I have a written a very simple threading and polymorphism example. All I wanted to do is to call a derived function from a different class which is containing that another class object. The program fails to compile with the message p does not name a type which I could not understand why.
Your error is in line:
p = &obj1;
It is better to write like this, it should help:
class caller
{
private:
derived obj1;
base *p = &obj1;
......
};
or initialize pointer in costructor:
class caller
{
private:
derived obj1;
base *p = nullptr;
caller() : p(&obj1) {}
......
};

Pass method as callback from one class to other class

I have 2 class, I would like to pass a method from one to other by callback!
See that I also wish to hold the address of this method using void (*callBack)();
I'm used to do this in C, but I dont know how to do this in c++;
#include <iostream>
using namespace std;
class A
{
private:
void (*callBack)(); //to hold the address of the method
public:
A();
void setCallBack(void(*cB)());
void useCallBack();
};
A::A()
{
}
void A::setCallBack(void(*cB)())
{
callBack = cB;
}
void A::useCallBack()
{
callBack();
}
class B
{
private:
A * Aguy;
public:
B();
void someMethod();
void otherMethod();
};
B::B()
{
Aguy = new A();
}
void B::otherMethod()
{
Aguy->setCallBack(someMethod);
Aguy->useCallBack()
}
void B::someMethod()
{
cout << "Hello. I'm from class b" << endl;
}
int main()
{
B Bguy;
Bguy.otherMethod();
return 0;
}
The problem is that:
void (*callBack)();
This is not a pointer to a method. This is a pointer to a function.
To have a pointer to a method you need to specify the class the method is in.
void (B::*callBack)();
Then when you call it you need to call it via an object.
void A::useCallBack(B* b)
{
(b->*callBack)();
}
But this is probably not what you want.
What you really want is a wrapper that encapsulates all this.
I would take a look at std::function. This will allow you to wrap a method call and an object into a single object that you can then call.
std::function<void()> callback;
Just replace all your occurrences of void(*cB)() with std::function<void()> then you can bind an instance of the object to the method at the call point.
Aguy->setCallBack(std::bind(&B::someMethod, this));
This also allows you to seemly pass any normal function or functor as a callback.
void print()
{ std:cout << "It worked\n";
}
...
Aguy->setCallBack(&print);
struct Printer
{
void operator()() const
{
std::cout << "It worked with obejct\n";
}
}
...
Aguy->setCallBack(Printer());
If you need to pass member function pointers see the modified code. it uses modern c++ constructs.
#include <iostream>
#include <functional>
using namespace std;
class A
{
private:
typedef std::function<void()> some_void_function_type;
some_void_function_type f_;
public:
A();
void setCallBack(some_void_function_type f);
void useCallBack();
};
A::A()
{
}
void A::setCallBack(some_void_function_type f)
{
f_ = f;
}
void A::useCallBack()
{
f_();
}
class B
{
private:
A * Aguy;
public:
B();
void someMethod();
void otherMethod();
};
B::B()
{
Aguy = new A();
}
void B::otherMethod()
{
Aguy->setCallBack(std::bind(&B::someMethod, this));
Aguy->useCallBack();
}
void B::someMethod()
{
cout << "Hello. I'm from class b" << endl;
}
int main()
{
B Bguy;
Bguy.otherMethod();
return 0;
}
See c++ - <unresolved overloaded function type> for details.
To quote the answer:
In C++, member functions have an implicit parameter which points to
the object (the this pointer inside the member function). Normal C
functions can be thought of as having a different calling convention
from member functions, so the types of their pointers
(pointer-to-member-function vs pointer-to-function) are different and
incompatible. C++ introduces a new type of pointer, called a
pointer-to-member, which can be invoked only by providing an object.
Put static on someMethod:
class B
{
private:
A * Aguy;
public:
B();
static void someMethod();
void otherMethod();
};
void B::otherMethod() {
Aguy->setCallBack(B::someMethod);
Aguy->useCallBack(); // adding missing semicolon
}