4

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.

Community
  • 1
  • 1
BlueSpud
  • 1,555
  • 3
  • 19
  • 44

5 Answers5

3

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.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
2
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.

kuhar
  • 338
  • 1
  • 2
  • 10
1

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?

Community
  • 1
  • 1
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • I have looked into some c++ texts, there are just some concepts I've always had a bit of trouble wrapping my head around, function pointers being a big one. – BlueSpud Jan 09 '14 at 22:02
  • @BlueSpud: The thing about function pointers is, if your doing it right (C++, that is), you almost never need them. Certainly not until you have advanced pretty far, and then you'll already know for the most part. – John Dibling Jan 10 '14 at 03:07
0

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.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • can I use this->&D::dosomethig? – BlueSpud Jan 09 '14 at 20:56
  • @BlueSpud No! Just check, how to call functions using (member) function pointers! – πάντα ῥεῖ Jan 09 '14 at 20:58
  • I know how to call member functions, I just want to do it inside the class. According to my compiler I just need to make it a const pointer, is that acceptable? – BlueSpud Jan 09 '14 at 21:03
  • @πάνταῥεῖ You do it inside the class as `this->member_function()` or just `member_function()` if its unambiguous. – David G Jan 09 '14 at 21:17
  • @BlueSpud Implicit `const` conversion from `this` should work as required and available (member function pointers need to have `const` signatures of course). – πάντα ῥεῖ Jan 09 '14 at 21:22
  • @πάνταῥεῖ what would that look like exactly? – BlueSpud Jan 09 '14 at 21:30
  • @BlueSpud It's not the matter about how you initialize the pointer (that should fairly work with the example I've given), but how you're going to call it! – πάντα ῥεῖ Jan 09 '14 at 21:34
  • @πάνταῥεῖ if I have pointer = &(this->something) The compiler says cannot create a non-constant pointer to a member function. So obviously there needs to be a const somewhere in there. – BlueSpud Jan 09 '14 at 21:40
  • @BlueSpud At this point, `this` refers to a non-const, thus this might cause the compilation error! – πάντα ῥεῖ Jan 09 '14 at 21:42
  • @πάνταῥεῖ The pointer would the need to be void(B::*pointer)() in order for it to work, and there is no available cast. – BlueSpud Jan 09 '14 at 21:53
0
#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.

Brandon
  • 22,723
  • 11
  • 93
  • 186