Say I have this class:
class Object {
public:
int x;
int y;
void update(SDL_Event);
void start();
};
I want to be able to make start and update change behavior from instance to instance.
I have tried using function pointers, like so:
class Object {
public:
int x;
int y;
void (*update)(SDL_Event);
void (*start)(void);
};
void teststart() {
x++;
return;
}
And in my main(), I do:
testlevel.objs[1].start = teststart;
But then, I cannot reference variables from inside the class.
I am sure there is something obvious I am overlooking, but searching online yields no results for when the pointer is in the class.
Maybe function pointers are not the right answer?
You would need to pass your functions a pointer/reference to the Object instance, eg:
class Object {
public:
int x;
int y;
void (*doupdate)(Object*, SDL_Event);
void (*dostart)(Object*);
void update(SDL_Event event) { if (doupdate) doupdate(this, event); }
void start() { if (dostart) dostart(this); }
};
void teststart(Object* obj) {
obj->x++;
}
void testupdate(Object* obj, SDL_Event event) {
// update obj as needed...
}
Object &obj = testlevel.objs[1];
obj.dostart = teststart;
obj.doupdate = testupdate;
Otherwise, use std::function with capturing lambdas instead:
#include <functional>
class Object {
public:
int x;
int y;
std::function<void(SDL_Event)> update;
std::function<void()> start;
};
Object *obj = &(testlevel.objs[1]);
obj->start = [obj](){
obj->x++;
};
obj->update = [obj](SDL_Event event){
// update obj as needed...
};
Related
Is there a way to declare member4 that only visible to Function1 and it is not shared by all instances?
class Test
{
public:
void Function1()
{
???? int member4 //visble to Function1 (single instance)
}
void Function2()
{
static int member3;// visble to Function2 (all instances)
}
private:
int member1; // visble to Function1 and Function2 (single instance)
static int member2;//visble to Function1 and Function2 (all instances)
};
Your question looks like an XY Problem. Anyway, here are two possible solutions.
First, you could wrap the field into a class and declare the method as a friend:
class Test {
public:
// Don't forget to init Data:
Test();
void function1();
void function2();
private:
class Data;
Data *data;
};
class Test::Data {
int get() { return 42; }
friend void Test::function1();
};
void Test::function1() {
int secretData = data->get();
}
void Test::function2() {
// Will not compile:
// int secretData = data->get();
}
This solution smells. Much better would be to extract the entity that has this secret member into a separate class:
class AnotherEntity {
public:
void function1() {
// use secretData here;
}
private:
int secretData;
};
class Test : public AnotherEntity {
public:
void function2();
private:
};
I want to register a callback handler (method) of the one class (Y) in another (X). I can't use std::function because of possible heap allocation and I must have an access to members of a class that registers the handler. I also want to avoid static functions.
I've came up with some workaournd but got stuck on calling the callback:
template<class T>
using clbkType = void(T::*)(void);
template<class T>
class X
{
public:
void registerClbck(clbkType<T> clbk) {
callback = clbk;
}
void call() {
callback(); // ERROR C2064: term does not evaluate to a function taking 0 arguments.
//(((X<T>*)this)->X<T>::callback)(); // same error
}
private:
clbkType<T> callback;
};
class Y
{
public:
Y() {
x.registerClbck(&Y::handler);
}
// just for a test: fire a callback in class X
void fire() {
x.call();
}
int getA() { return a; }
private:
int a{ 0 };
X<Y> x{};
void handler() {
a = 5;
}
};
int main()
{
Y y;
y.fire();
return y.getA();
}
link to code: https://godbolt.org/z/PhY41xsWE
PS. I'm not sure if this is a safe solution, so please put any comment on that.
Thanks!
The member function pointer needs a specific class object to invoke, so you need to do this:
template<class T>
class X
{
public:
// ...
void call(T& obj) {
(obj.*callback)();
}
// ...
};
class Y
{
public:
// just for a test: fire a callback in class X
void fire() {
x.call(*this);
}
// ...
};
Demo.
The member function pointer need an instance to be called on.
If you want to bind the instance, here is a possible way to implement it.
template<typename T>
struct member_callback {
T* instance;
void(T::*callback)();
void operator()(){(instance->*callback)();}
};
template<typename T>
struct X{
void registerClbck(member_callback<T> clbk) { callback = clbk; }
void call() { callback(); }
member_callback<T> callback;
};
struct Y{
public:
Y() { x.registerClbck({this,&Y::handler}); }
void fire() { x.call(); }
int getA() { return a; }
private:
int a{ 0 };
X<Y> x{};
void handler(){ a = 5; }
};
int main()
{
Y y;
y.fire();
return y.getA();
}
Given a class:
class myClass{
// ...
private:
int helperFuncForA();
int secondhelperFuncForA();
public:
void A();
// ...
};
Suppose that the helper functions are not used outside of A; how do I encapsulate them such that calling them outside of A is impossible? Do I do:
class myClass{
// ...
public:
class {
private:
int helperFuncForA();
int secondhelperFuncForA();
public:
void call();
} A;
// ...
};
and then call by writing:
myClass obj;
obj.A.call();
? Perhaps, I could overload A's () operator instead of making the call() function for convenience. What is the correct way?
The correct way is using of lambdas:
class myClass{
// ...
private:
// remove from here
//int helperFuncForA();
//int secondhelperFuncForA();
public:
void A();
// ...
};
// somewhere
void myClass::A()
{
auto helperFuncForA = [this]() -> int
{
//...
return 1;
};
auto secondhelperFuncForA = [this]() -> int
{
//...
return 2;
};
//...
int x = helperFuncForA();
x += secondhelperFuncForA();
}
If some method can only be used by in the function void A(), you probably need a class.
But you can do something like this if you want :
#include <iostream>
class ClassTest
{
public:
struct A{
private:
void helperFunc() {
std::cout << "Executing Helper Func " << std::endl;
}
public:
void operator() (){
helperFunc();
}
};
A a;
void classFunc(){
//a.helperFunc(); <- Impossible helperFunc private
a();
}
};
int main()
{
ClassTest c;
c.classFunc();// Print : Executing Helper Func
//OR
c.a();// Print e: Executing Helper Func
}
Is there a way to use an = type assignment instead of this syntax:
void triggerAttack() { adsr.triggerAttack(); }
I was hoping to do something like:
void triggerAttack() = adsr.triggerAttack
std::function<void()> triggerAttack = adsr.triggerAttack
void(*triggerAttack)() = adsr.triggerAttack
but nothing compiles!
example code:
class LinearADSR
{
public:
void triggerAttack() { }
};
class JerobeamBlubb : public gen
{
public:
void triggerAttack() { adsr.triggerAttack(); }
protected:
LinearADSR adsr;
};
In general, a member function pointer differs from usual pointers, since it has to be used with an instance of its class.
So change your code to this:
class LinearADSR
{
public:
void triggerAttack() { }
};
class JerobeamBlubb
{
public:
void (LinearADSR::*triggerAttack)();
protected:
LinearADSR adsr;
};
int main()
{
JerobeamBlubb a;
a.triggerAttack = &LinearADSR::triggerAttack;
}
About your failed attempts:
void triggerAttack() = adsr.triggerAttack; is invalid syntax
std::function<void()> triggerAttack = adsr.triggerAttack fails because triggerAttack is a member function, and not a usual function. You need an instance of its class as I explained before.
void(*triggerAttack)() = adsr.triggerAttack fails for the same reason as above.
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
}