I want to pass a member function of class A to class B via a function pointer as argument. Please advise whether this road is leading somewhere and help me fill the pothole.
#include <iostream>
using namespace std;
class A{
public:
int dosomeA(int x){
cout<< "doing some A to "<<x <<endl;
return(0);
}
};
class B{
public:
B(int (*ptr)(int)){ptr(0);};
};
int main()
{
A a;
int (*APtr)(int)=&A::dosomeA;
B b(APtr);
return 0;
}
This brilliant piece of code leaves me with the compiler error:
cannot convert int (A::*)(int)' toint (*)(int)' in initialization
Firstly I want it to compile.
Secondly I don't want dosomeA to be STATIC.
Pointers to members are different from normal function pointers. As the compiler error indicates the type of &A::dosomeA is actually int (A::*)(int) and not int (*)(int).
Inside B's constructor you need an instance of A to call the member on using one the .* or ->* operators.
E.g'
B(int(A::*ptr)(int))
{
A atmp;
(atmp.*ptr)(int);
}
http://www.parashift.com/c++-faq-lite/pointers-to-members.html
You don't have a pointer to a function that returns an int and takes an int. You have a pointer to a member-function that returns an int and takes an A* and an int. Not only do you need to fix the type of your pointer, B needs to provide an A* to serve as dosomeA's this parameter.
Boost::bind has some functionality meant to simplify using function pointers in general, and they provide support for pointers to member functions. See here.
Related
I have the following class structure
class containingClass
{
int func1(int a);
containedClass containedClassObject;
}
I want to access func1 in containedClass objects. What will be the best way to achieve that?
A naive solution that comes to mind is to pass a function pointer to the containedClass's constructor, but then I get into a circular definition, as I need to pass a pointer to an object of the containingClass as well.
Any suggestions?
The containedClass required a contract/API/function to be fulfilled by the int func1(int) member of the containingClass. Unless the containedClass explicitly requires access to an instance of the containingClass for other purposes, the access can be provided via lambda (or std::bind) and the containedClass can have a std::function with the correct signature member that holds the lambda.
The only "trick" here would be to ensure that the lifetime of the objects are managed appropriately, i.e. the lifetime of the containingClass instance is at least as long as required for use in the containedClassObject object.
A sample;
#include <functional>
class containedClass {
std::function<int(int)> functor_;
public:
void setter(std::function<int(int)> functor) { functor_ = functor; }
};
class containingClass
{
int func1(int a);
containedClass containedClassObject;
public:
containingClass()
{
containedClassObject.setter([this](int a) -> int { return this->func1(a); });
}
};
Even if this already over a year old, I would like to help other seraching people.
Here is another example using a reference to the containing class. Tested with mingw32-g++ 4.9.2 and -std=c++98. Means it should work also with c++0x and c++11
#include <string>
#include <iostream>
using namespace std;
class clsDog;
class clsEar{
public:
clsDog& myDog;
clsEar(clsDog &dog);
};
class clsDog{
public:
clsEar ear;
void pain(string fromPart){
cout << "dog has pain in his " << fromPart << endl;
}
clsDog():ear(*this){};
};
clsEar::clsEar(clsDog &dog): myDog(dog){
myDog.pain("ear");
}
int main(){
clsDog dog;
}
First class clsDog makes it available for reference and pointers. NOT for actual values like non reference member variables.
In class clsEar a reference to clsDog is created using clsDog& myDog. The constructor can set the reference pointer in the initializer list. It is important that the containing class clsDog is passed by reference otherwise the compiler tell you that the class incomplete.
Because clsEar is now fully defined a normal member variable of clsEar can be defined in clsDog. Because clsEar's constructor needs a reference to clsDog it must be passed to it's constructor. This is done in the initialisier list of clsDog's constructor by passing *this.
Last but not least the implementation of clsEar::clsEar must be done. It is necessary to do this after the complete definition of clsDog to call the member functions or access member varibales of clsDog in clsEar. Otherwise the compiler will tell you again, that the class clsDog is of incomplete type.
class A
{
public:
A();
void Func1(int,int);
void Func2(long,long);
private:
...
};
<implementation here>
In main:
std::vector<std::function<void(void)>> fl;
A a;
fl.push_back(std::bind(&a.Func1, 1,1));
Gives the error:
ISO C++ forbids taking the address of a bound member function to form a pointer to member function
Solution?
Edit: changed "A a();" to "A a;". No constructor here :P
Edit:
Selected Praetorian's reply as answer because it solves the problem.
Dietmar Kühl's is a good solution too but not the actual answer to the question.
Gotta be fair :D
Func1 is a non-static member function, so it must be invoked on an instance of A, which you'll need to bind as the first argument (the this pointer). Also, when creating a pointer to member function, the syntax is &ClassName::MemFuncName.
So you need
fl.push_back(std::bind(&A::Func1, &a, 1, 1));
Make sure that the lifetime of a does not end before you invoke the bound function.
Two issues. First,
A a();
is a function declaration. You need
A a;
Then,
fl.push_back(std::bind(&A::Func1, &a, 1,1));
You could also just not use std::bind():
std::vector<std::function<void(void)>> fl;
A a{};
fl.push_back([&](){ a.Func1(1, 1); });
The code show references a on the stack. That's OK when the function object doesn't outlive a. If that can't be guaranteed you may want to replace the & by = which would copy the object. BTW, the subtle change from () to {} causes the code to declare a an object of type A rather than as a function taking no argument and returning A.
unfortunately C++ doesn't have a syntax like that. A complete example with the correct syntax would look like this:
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
class A
{
public:
A() {}
void Func1(int,int) {}
void Func2(long,long) {}
};
int main()
{
std::vector<std::function<void(void)>> fl;
A a;
fl.push_back(std::bind(&A::Func1, &a, 1,1));
return 0;
}
You need to provide two things (at least): 1) the pointer to member function 2) the implicit "this" pointer, i.e., the object you want to call the method on.
Then you can add the parameters you want to bind.
Note also that unfortunately you can't make an instance of "A" with "A a();" This is the "most vexing parse". The correct way is "A a;" or "A a{};"
My code contains the following:
1) A.h (cannot be changed by me as it's defined by somebody else)
typedef void (*fnctPtr)(int input);
class A
{
A(fnctPtr func); //Constructor for A
//... Other details omitted
};
2) B.h (my code)
#include "A.h"
class B
{
public:
B() : m_a(m_private_method){}; //Ptr to non static method.
void m_private_method(int input);
A m_a; //Member variable
};
3) A simple main.cpp declaring and instance of B
#include <iostream>
#include "B.h"
int main()
{
B b;
return 0;
}
It does not compile, as m_a requires initialization with a fnct pointer of type void (*)(int input), not void (B::*)(int input).
Any advice on how to achieve what I want?
Thanks
If you're really stuck with typedef void (*fnctPtr)(int input);, then you have to provide a pointer to a function that takes a int as parameter and returns nothing.
When you' providing a pointer-to-member function of class B taking an int and returning nothng, you really provide either something that can be seen as:
either function taking two arguments, the instance of the classB and an int.
or a virtual function that need to lookup in B instance to know what function taking two arguments (B and int) to call.
There is no way to make any of those fit into the first definition.
You may find a hack (keeping an instance globally and using it inside an helper function would be one), but this is highly dependent of the full problem.
I have a class containing several very similar functions and a couple other functions that take those interchangeably functions as input.
A simpler example:
class functions{
public:
int a();
int b();
int F(int (*f)() ); //f can only be a() or b()
};
Before I put them in a class, I had something like
if(f!=a || f!=b) cout<<"error";
With the class, it seems to just get more complicated, since I believe I now need to pass a class instance or something to get rid of my error: invalid use of member function
I have just started to learn about enumerated lists, and it seems like that would do the job if I was dealing with normal variables. Can I create an enum of functions?
What is the best way to restrict functions that can be passed to another function?
I'm pursuing the static cast method, but still needing help with int F( int(*f)() );
int functions::F(int (functions::*f)() )
{
if(f==functions::a)
//gives error: invalid operands of types 'int (functions::*)()'
// and 'int (int(*)()' to binary operator =='
int x=f();
//gives error: must use ‘.*’ or ‘->*’ to call pointer-to-member
//function in 'f(...)'
int y=(functions.*f)();
//gives error: expected primary-expression before ‘.*’ token
return 0;
}
It really depends on what you want to achieve:
I'd say largely that this sort of restriction is best validated by code review rather than coding...
The other solution is to not use that construct at all, and making a Fa() and Fb() function that calls the (private) a() and b() member functions.
And the remainder of the question is "how do I call a member function of a class" -the answer to which depends highly on whether Functions has member variables that are used in a() and b() or not. If there are no member functions, then declaring the a() and b() members as static will work. On the other hand, if you want to use a "member function pointer", the syntax is int (Functions::*f) and &Functions::a respectively, and the call has to be made using an instance of Functions. so if we have Functions fun, you'd do fun.*f(). Or (*this).*f(), insice F().
You may wrap the accepted function in a class:
#include <iostream>
class Functions
{
public:
int a() { return 0; }
int b() { return 1; }
};
class Accept
{
public:
typedef int (Functions::*AcceptFunction)();
int apply(Functions& object, AcceptFunction function) {
return (object.*function)();
}
};
int main()
{
Functions functions;
Accept accept;
std::cout << accept.apply(functions, &Functions::b) << std::endl;
}
(Feel free to bundle it by making Functions a nested class in Accept)
I'm just learning C++ and I'm having difficulties regarding pointers to methods. Lets say:
class One {
public:
int Add (int a, int b) {return a+b;}
};
typedef int (One::*pAdd) (int, int);
class Other {
public:
int Next (pAdd funct, int c){ return funct (c, 1);}
};
int main (){
One one;
Other other;
other.Next(one.Add, 2);
return 0;
}
I have a number of problems, as reported by my MinGW. First, I'm not invoking funct correctly, as compiler insists on using .* or ->* . Have no idea how to incorporate this request and any help is welcomed. Now, I could solve my problems by making methods static to use c-style pointers or pass objects and invoke methods from within Next, but I want to understand pointers to methods. Basically, I'm puzzled why one.Add is not an acceptable input. Method to call is unambiguously defined (.Add) and conforms my typedef. Also, I'm providing instance of class (one) from typedef thus providing context in which method is to be executed. But compiler output looks like I didn't only miss the syntax, but like I missed the concept. So, how to pass pointer to method with object as context as a single argument?
The main problem here is that member functions are not associated with an object instance, they are just function pointers with a slightly different signature.
So, when you want to call a member function you need two things: a pointer to the member function and the object instance in which to call it.
I changed your code sample a bit:
#include <iostream>
class One {
public:
int Add (int a, int b) {return a+b;}
};
typedef int (One::*pAdd) (int, int);
class Other {
public:
int Next (One one, pAdd funct, int c){
return (one.*funct)(c, 1);
}
};
int main (){
One one;
Other other;
std::cout << other.Next(one, &One::Add, 2) << std::endl;
return 0;
}
And it works now. It can probably be improved a bit, but I think you can take it from here.
I recommend that you read Pointers to member functions section of the c++ faq lite, which explains this very well.
So, how to pass pointer to method with object as context as a single argument?
Using just member-function pointers, you can't. Although your syntax looks like something that should do that, it just isn't allowed. You need an object to apply the function to:
class Other {
public:
int Next (pAdd funct, One & o, int c){ return (o.*funct) (c, 1);}
}
int main (){
One one;
Other other;
other.Next(&One::Add, one, 2);
}
If you want to create a function object that calls a particular member function of a particular object, then one possibility is to use std::bind (or boost::bind if you can't use C++11 yet):
#include <functional>
class Other {
public:
int Next (std::function<int(int,int)> funct, int c){ return funct (c, 1);}
};
int main (){
One one;
Other other;
using namespace std::placeholders;
other.Next(std::bind(&One::Add, &one, _1, _2), 2);
}
or a lambda:
other.Next([&](int a, int b){return one.Add(a,b);}, 2);
Pointers to members need an instance to operate on. Essentially, they are functions which take an addition parameter which becomes the implicit this pointer. To call a function through a pointer to member for the current object you can use code like this:
(this->*funct)(c, 1);
(you'd access member variables similarly but without a function call).
The object you call the member on isn't part of the pointer to member. As a result you need to get it something like this:
&One::Add
This becomes more interesting if the member function is overloaded: in this case you need to provide a context from which the overload can be determined when taking the address. I tupically use a static_cast<>() for this:
static_cast<int (One::*)(int,int)>(&One::Add)
You have a bunch of problems here: one.Add is a member function and
you cannot just invoke it. You need to have a pointer to the class to
invoke it on as well. Also, you need to use the special operator.*
or operator->*. You can also not take the address of a bound member
function.
All in all, you should use a template and boost/std::bind to make
all this bearable or stay away from it.
Here is modified, working code:
class One {
public:
int Add (int a, int b) {return a+b;}
};
typedef int (One::*pAdd) (int, int);
class Other {
public:
int Next (One* one, pAdd funct, int c){ return (one->*funct)(c, 1);}
};
int main (){
One one;
Other other;
other.Next(&one, &One::Add, 2);
return 0;
}