Reputation: 1623
So I'm in a bit of a dilemma right now. I want to make a function pointer, but I want to make it to a virtual function. Not necessarily the virtual function itself, but the derived one. I tried just making the pointer, but the function needs to be static. When I try to make a static virtual function, the compiler yells at me. I also don't want to make the function pointer class specific so conceivably other classes could use the pointer. Here is what I mean in pseudocode:
class C
{
public:
virtual void something();
};
class B : public C
{
public:
void something();
};
class D
{
public:
void something();
};
int main()
{
void(*pointer)();
B b;
D d;
pointer = b.something.
pointer();
pointer = d.something;
pointer()
}
Something is not a static method but I want the pointer to be able to point to it. Also the pointer can point to other class methods that are also not static. Is there anything I can do with this?
EDIT I finally was able to figure out how to do this. I had to use std::function. This should also work for just regular member functions, not necessarily virtual one. Here is what it would look like:
class A
{
public:
virtual void something(int i);
};
class B
{
virtual void somethingElse(int i);
}
//This isn't needed, it just saves typing if you have multiple pointers
typedef std::function<void(int)> functionType
functionType* pointer;
int main()
{
B b;
A a;
pointer = std::bind(&A::something,&a,std::placeholders::_1);
pointer(1)
pointer = std::bind(&B::somethingElse,&b,std::placeholders::_1);
pointer(4)
}
Theres quite a bit on the internet on std::bind, so if you're curious you can read about it. I found this particularly helpful, as it has a very similar solution to what I have. std::function to member function Thanks to all who have helped.
Upvotes: 4
Views: 2371
Reputation: 101446
There are so many things wrong here it's hard to know where to begin.
This:
void(*pointer)();
does not declare a pointer-to-member-function. It declares a pointer-to-free-function (eg, non-member function). These two types of pointers are completely unrelated, and you cannot convert between the two. You can not assign the address of a member function to a pointer-to-free-function, or vice versa.
You need to declare a pointer-to-member with special syntax. The old (C++03) syntax would be:
void (C::*memFn)()
However, since the type of the pointer includes information about the class that the function is a member of, now you can't assign the address D::something()
to memFn
-- C
and D
are completely unrelated as well.
You mentioned that you wanted to create a "static virtual method." There's no such thing. In fact the two concepts "static" and "virtual" are almost completely orthogonal to each other. The idea simply makes no sense. It's like saying you want to plant an apple hammer.
Why are you trying to use the D
object as if it were a B
object? D
and B
are completely unrelated. It seems to me like what you really should be trying to do is have an abstract base class, A
, and 2 concrete implementations of that ABC, B
and C
. Then a pointer to an A
could point to either a B
or a C
, and you could call virtual
methods of the same name and get different behavior.
Finally, for the last couple of days you have posted questions that indicate that you are struggling to learn the language by banging out some code and trying to fix whatever compiler errors result. (I might be thinking of someone else, if so I'm sorry) That's not going to work. Have you taken my advice and gotten a good C++ text yet?
Upvotes: 1
Reputation: 23498
#include <iostream>
class A
{
private:
int i;
protected:
void (A::*ptr)();
public:
A() : i(0), ptr(&A::methodOne) {}
virtual ~A(){}
void move_ptr()
{
switch(++i)
{
case 0: {ptr = &A::methodOne;} break;
case 1: {ptr = &A::methodTwo;} break;
case 2: {ptr = &A::methodThree;} break;
case 3: {ptr = &A::nonVirtual;} break;
default: {ptr = &A::methodOne; i = 0;} break;
}
}
void call() {(this->*A::ptr)();}
virtual void methodOne() {std::cout<<"A::methodOne\n";}
virtual void methodTwo() {std::cout<<"A::methodTwo\n";}
virtual void methodThree() {std::cout<<"A::methodThree\n";}
void nonVirtual() {std::cout<<"A::nonVirtual\n";}
};
class B : public A
{
public:
B() : A() {}
virtual ~B(){}
virtual void methodOne() {std::cout<<"B::methodOne\n";}
virtual void methodTwo() {std::cout<<"B::methodTwo\n";}
virtual void methodThree() {std::cout<<"B::methodThree\n";}
void nonVirtual() {std::cout<<"B::nonVirtual\n";}
};
int main()
{
A a;
a.call();
a.move_ptr();
a.call();
a.move_ptr();
a.call();
a.move_ptr();
a.call();
B b;
b.call();
b.move_ptr();
b.call();
b.move_ptr();
b.call();
b.move_ptr();
b.call();
}
Prints:
A::methodOne
A::methodTwo
A::methodThree
A::nonVirtual
B::methodOne
B::methodTwo
B::methodThree
A::nonVirtual
I'll leave it to you to figure out why the last line is A::nonVirtual
instead of B::nonVirtual
. Once you figure that out, you'll already know how to fix it.
Upvotes: 0
Reputation: 153792
You won't be able to assign a pointer-to-member function to a normal function pointer: function pointers don't take any additional arguments while member function take an implicit this
pointer as argument. You might want to use a std::function<...>
, though:
std::function<void()> pointer;
B b;
pointer = std::bind(&C::something, &b);
pointer();
D d;
pointer = std::bind(&c::something, &d);
pointer();
You could avoid using std::function<...>
if you pass a pointer to the object and a suitable member function pointer around and there is common base class (while the code above works with the missing inheritance, the code below requires that C
is a base of D
):
void (C::*member)() = &C::something;
C* c = &b;
(c->*member)(); // calls b.something() using B::something()
c = &d;
(c->*member)(); // calls d.something() using D::something()
C++ doesn't have a notation using &object.member
to get the address of a readily bound member function. ... and, even if it did, its type wouldn't be void(*)()
either.
Upvotes: 3
Reputation: 428
void(B::*bPointer)();
void(D::*dPointer)();
B b;
D d;
bPointer = &B::something;
(b.*bpointer)();
dPointer = &D::something;
(d.*dPointer)();
You can also use std::mem_fn and std::bind.
Upvotes: 2
Reputation: 1
S.th. like
pointer = &D::dosomething;
May be??
Note:
You'll need to have an actual instance of D
to call non-static class members.
Upvotes: 0