I'm trying to make a simple callback in C++ but I'm having issues doing it as I want to.
Essentially I want something like this:
class A{
void A::AddCallback(void (*callBackFunction)(string)){
/*Code goes here*/
}
}
And class B
#include "A.h"
class B{
B::B(){
A childObject;
childObject(MyCallBackFunction);
}
B::MyCallBackFunction(string arg){
/*Code goes here*/
}
}
I know that usually you would want to define the header of AddCallback with something like B::callBackFunction but I do need to import A in B so I it would be awkward to have both classes import each other. I know I've seen this before but I cant get the syntax right
Here is one option using a static member function:
#include <string>
struct A
{
void AddCallback(void (*cb)(std::string));
};
struct B
{
A a;
B() { a.AddCallback(&B::MyFun); }
static void MyFun(std::string);
};
If you want a non-static member function, then you first need to decide on which instance of B you want the member function to be invoked. For example, to invoke it on the object whose constructor registers the callback:
#include <functional>
#include <string>
struct A
{
void AddCallback(std::function<void(std::string)>);
};
struct B
{
A a;
B() { a.AddCallback(std::bind(&B::MyFun, this, std::placeholders::_1)); }
void MyFun(std::string);
};
you must call void A::AddCallback and pass callback instead of passing argument in childObject(MyCallBackFunction);
Related
I'm currently working on a project that has several classes, and at times, I have to call functions from other classes to make things work. I want to know if the way I'm doing it is efficient, or if there is another way I should be doing this. Here's an example
class FirstClass{ // FirstClass.cpp
public:
void aFunction(){
std::cout << "Hello!";
}
private:
}
Let's say I wanted to call aFunction in another class, I'd do this:
#include "FirstClass.cpp"
class SecondClass{ //SecondClass.cpp
public:
FirstClass getFirstClass;
// I would then use getFirstClass.aFunction();
// whenever I want to call.
private:
}
I don't feel like this is very productive. Is there a better way of doing this?
First of all why including source file FirstClass.cpp?
The proper way is to create a header file FirstClass.h and a source file FirstClass.cpp and include the header inside the source and in main.cpp.
Second: A member function is a member function it is a member of an object so you need an instance of that class to call its member. If you don't want to instantiate the class then declare the member function as a static function then you can either call it using an object or directly using class name followed by scope operator: FirstClass::aFunction().
// FirstClass.h
class FirstClass{ // FirstClass.cpp
public:
void aFunction();
}
// FirstClass.cpp
#include "FirstClass.h"
void FirstClass::aFunction(){
std::cout << "Hello!";
}
// SecondClass.h
#include "FirstClass.h"
class SecondClass{
public:
void foo();
private:
FirstClass getFirstClass;
};
// SecondClass.cpp
void SecondClass::foo()
{
getFirstClass.aFunction();
}
To make it a static:
struct A
{
static void do_it(){std::cout << "A::do_it()\n";}
};
struct B
{
void call_it(){ A::do_it();}
};
There's nothing with "productivity" to whether have a static or non-static data/function member.
The semi-colon is not redundant at the end of class body so you need t add them: class FirstClass{ }; class SecondClass{};.
This is related to my last post that you can find here: Creating an unordered_map of std::functions with any arguments. I have now gone ahead and extended this out to classes. So let's say I have three different classes. And these classes all have different methods except for getVariable() and setVariable(int). So for this example we will class them ClassA, ClassB, and ClassC.
I also have a base class which I want to use as my driver. Essentially, if I want to set the variable between ClassA and ClassC I would call the base class' setVariable function.
#ifndef BASE_CLASS_HPP
#define BASE_CLASS_HPP
#include <unordered_map>
#include <functional>
#include <utility>
#include <string>
#include <any>
template<class A, class B>
class BaseClass
{
public:
BaseClass() { bindThem(); }
std::pair<int,int> getValue()
{
// return classA and ClassB's values
}
void setValue(int newVal)
{
auto iter = functions.equal_range("setValue");
std::any_cast<void(*)(int)>(mapIter->second)(newVal);
}
private:
std::unordered_multimap<std::string,std::any> functions;
void bindThem()
{
functions.emplace("setValue",&A::setValue);
functions.emplace("setValue",&B::setValue);
functions.emplace("getValue",&A::getValue);
functions.emplace("getValue",&B::getValue);
}
};
I then have in main:
#include <iostream>
#include "baseClass.hpp"
#include "classA.hpp"
#include "classB.hpp"
#include "classC.hpp"
int main()
{
ClassA a;
ClassB b;
ClassC c;
c.setValue(20);
BaseClass<ClassA,ClassB> base1;
BaseClass<ClassA,ClassC> base2;
base1.setValue(15);
auto values = base1.getValues();
}
I can place the functions withing my map, however, when I try to any_cast I don't get anything in return. I also tried:
std::any_cast<void(A::*)(int)>(mapIter->second)(newVal);
But that also gives me a compiler error of must use .* or ->* and I have tried everything to get it to compile and I don't really know what I am doing wrong. I also realized, if I called it that way, then I wouldn't be able to access B's setVariable function since I am using A's namespace.
Is there anyway I can get this to work how I want it to? I am essentially trying to modify those class values without having to make any copies of those classes and instead directly modify them from within this driver.
I still don't quite understand the purpose of such structure, but here an option how to make it at least compile:
#include <unordered_map>
#include <functional>
#include <utility>
#include <string>
#include <any>
template<class A, class B>
class BaseClass
{
public:
BaseClass() { bindThem(); }
std::pair<int,int> getValue()
{
auto range = functions.equal_range("getValue");
return
{
(a.*std::any_cast<int(A::*)()>(*range.first))(),
(b.*std::any_cast<int(B::*)()>(*range.second))()
};
}
void setValue(int newVal)
{
auto range = functions.equal_range("setValue");
(a.*std::any_cast<void(A::*)(int)>(*range.first))(newVal);
(b.*std::any_cast<void(B::*)(int)>(*range.second))(newVal);
}
private:
std::unordered_multimap<std::string,std::any> functions;
void bindThem()
{
functions.emplace("setValue",&A::setValue);
functions.emplace("setValue",&B::setValue);
functions.emplace("getValue",&A::getValue);
functions.emplace("getValue",&B::getValue);
}
A a;
B b;
};
class ClassA
{
public:
void setValue(int){}
int getValue() {return 0;}
};
class ClassB
{
public:
void setValue(int){}
int getValue() {return 1;}
};
int main()
{
BaseClass<ClassA, ClassB> x;
x.setValue(3);
auto i = x.getValue();
}
Please note several things:
I've added members to BaseClass since to call member functions you need an object to be called on.
I'm using first and last iterators of the range from equal_range, but the order of elements in that range is implementation defined. So to make things work you need to take care of distinguishing which container element corresponds to class A and which to class B.
I'm trying to set a reference of a non-static function in c++. The function I'm referencing is not from the same c++ file, and I get and error saying :
Cannot create a non-constant pointer to member function.
Main.cpp
#include <iostream>
#include "Test.hpp"
class testClass {
public:
void (*update) (void);
};
int main() {
testClass tc;
test t;
tc.update = &t.update; //This is where the error occurs
return 0;
}
Test.hpp
#ifndef Test_hpp
#define Test_hpp
#include <stdio.h>
class test {
public:
void update() {
//Do something
}
};
#endif /* Test_hpp */
My question is how do you do this without setting update in test class to static?
static void update() {
//Do something
}
Using this code it works, but like I've stated I do not want this functiont to be static.
EDIT :
Because I'm stupid I failed to mention that the class test should be able to be different. Also to the answers I got already I learned that tc.update = &t.update; is wrong.
For Example :
#include <iostream>
#include "Test.hpp"
#include "anotherTestClass.hpp"
//I do not want to use templates if possible
class testClass {
public:
void (*update)(void);
};
int main() {
testClass tc;
test t;
tc.update = &test.update; //I know this is wrong now.
testClass tc2;
anotherTestClass atc;
tc2.update = &atc.update;
//p.s. I'm bad with c++
}
And the error i get now is.
Assigned to 'void (*)()' from incompatible type 'void (test::*)()'
One more thing is I'm using XCode to program, which I believe uses LLVM-GCC 4.2 as the compiler.
class test {
public:
void update() {
//Do something
}
};
class testClass {
public:
void (test::* update) (void);
};
int main() {
testClass tc;
test t;
tc.update = &test::update;
return 0;
}
Your approach is essentially wrong.
Member Function Pointers.
The member in the testClass:
void (*update) (void);
is a function pointer, which is different to a method function pointer. That why in order to compile you should switch to a static method (which is essentially a "normal" function).
A method function pointer should containt the static information about the class the method belongs.
Practically the right way is:
void (test::* ptr_method)(void); // a member pointer to test class
In that way the variable named ptr_method is a method of the class test pointer.
Then,
Get the Address of a method.
Your statement:
tc.update = &t.update; //This is where the error occurs
is simply wrong. The address of a class method is something which is not related with the object of that class.
You can obtain the address of a method with the syntax:
&CLASS_NAME::METHOD_NAME;
Indeed, that statement should be something like:
tc.update = &test::update;
Additional suggestions.
Call a method by means of a method pointer.
Once you have a method pointer it is not so immediate to call the method associated with it.
As I said before, the address of the method is not related with the object of that class, so if you want to call the method you need to provide to the compiler the information about the object on which the method has to be called.
The syntax is something like:
(OBJECT.*METHOD_POINTER)(ARGS...);
Here, I propose a simple demo which shows all what I've just said.
The code describes two classes that implement callback function, the function must should be member function in the class parameter that passed in template.
Below the code i attached the relevent error message i get.
a.h
template <class CLASSNAME>
class a
{
public:
typedef void (CLASSNAME::*myFunction)();
a(CLASSNAME& myObject, myFunction callback) :
m_myObject(myObject)
{
m_myFuntion = callback;
}
void update()
{
(m_myObject).*(m_myFuntion);
}
myFunction m_myFuntion;
CLASSNAME& m_myObject;
};
dummy.h
#include <stdio.h>
class dummy
{
public:
dummy()
{
var = 14;
}
void func()
{
printf("func!!");
}
int var;
};
main.cpp
#include <cstdlib>
#include "a.h"
#include "dummy.h"
void main()
{
dummy dum;
a<dummy> avar(dum, &(dummy::func));
avar.update();
system("pause");
}
i am trying to implement the callback function and i get the following error message:
C2298 missing call to bound pointer to member function
what the problem is?
You have a lot of parentheses, they're just not in the right place. The correct syntax for calling a pointer-to-member function is:
void update()
{
(m_myObject.*m_myFuntion)();
}
You are using parentheses in the wrong places:
This:
a<dummy> avar(dum, &(dummy::func));
should be this:
a<dummy> avar(dum, &dummy::func);
And this:
(m_myObject).*(m_myFuntion);
should be:
(m_myObject.*m_myFuntion)();
Live Example
Very new to c++ having trouble calling a function from another class.
Class B inherits from Class A, and I want class A to be able to call a function created in class B.
using namespace std;
class B;
class A
{
public:
void CallFunction ()
{
B b;
b.bFunction();
}
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
It all looks fine on screen (no obvious errors) but when I try to compile it i get an error C2079 'b' uses undefined class B.
I've tried making them pointers/ friends but I'm getting the same error.
void CallFunction ()
{ // <----- At this point the compiler knows
// nothing about the members of B.
B b;
b.bFunction();
}
This happens for the same reason that functions in C cannot call each other without at least one of them being declared as a function prototype.
To fix this issue we need to make sure both classes are declared before they are used. We separate the declaration from the definition. This MSDN article explains in more detail about the declarations and definitions.
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{ ... }
};
void A::CallFunction ()
{
B b;
b.bFunction();
}
What you should do, is put CallFunction into *.cpp file, where you include B.h.
After edit, files will look like:
B.h:
#pragma once //or other specific to compiler...
using namespace std;
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
B.cpp
#include "B.h"
void A::CallFunction(){
//use B object here...
}
Referencing to your explanation, that you have tried to change B b; into pointer- it would be okay, if you wouldn't use it in that same place. You can use pointer of undefined class(but declared), because ALL pointers have fixed byte size(4), so compiler doesn't have problems with that. But it knows nothing about the object they are pointing to(simply: knows the size/boundary, not the content).
So as long as you are using the knowledge, that all pointers are same size, you can use them anywhere. But if you want to use the object, they are pointing to, the class of this object must be already defined and known by compiler.
And last clarification: objects may differ in size, unlike pointers. Pointer is a number/index, which indicates the place in RAM, where something is stored(for example index: 0xf6a7b1).
class B is only declared but not defined at the beginning, which is what the compiler complains about. The root cause is that in class A's Call Function, you are referencing instance b of type B, which is incomplete and undefined. You can modify source like this without introducing new file(just for sake of simplicity, not recommended in practice):
using namespace std;
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
// postpone definition of CallFunction here
void A::CallFunction ()
{
B b;
b.bFunction();
}
in A you have used a definition of B which is not given until then , that's why the compiler is giving error .
Forward declare class B and swap order of A and B definitions: 1st B and 2nd A. You can not call methods of forward declared B class.
Here's my solution to the issue. Tried to keep it straight and simple.
#include <iostream>
using namespace std;
class Game{
public:
void init(){
cout << "Hi" << endl;
}
}g;
class b : Game{ //class b uses/imports class Game
public:
void h(){
init(); //Use function from class Game
}
}A;
int main()
{
A.h();
return 0;
}
You can also have a look at the curiously recurring template pattern and solve your problem similar to this:
template<typename B_TYPE>
struct A
{
int callFctn()
{
B_TYPE b;
return b.bFctn();
}
};
struct B : A<B>
{
int bFctn()
{
return 5;
}
};
int main()
{
A<B> a;
return a.callFctn();
}