Calling base class definition of virtual member function with function pointer
Asked Answered
S

6

22

I want to call the base class implementation of a virtual function using a member function pointer.

class Base {
public:
    virtual void func() { cout << "base" << endl; }
};

class Derived: public Base {
public:
    void func() { cout << "derived" << endl; }

    void callFunc()
    {
        void (Base::*fp)() = &Base::func;
        (this->*fp)(); // Derived::func will be called.
                       // In my application I store the pointer for later use,  
                       // so I can't simply do Base::func().
    }
};

In the code above the derived class implementation of func will be called from callFunc. Is there a way I can save a member function pointer that points to Base::func, or will I have to use using in some way?

In my actual application I use boost::bind to create a boost::function object in callFunc which I later use to call func from another part of my program. So if boost::bind or boost::function have some way of getting around this problem that would also help.

Sestertium answered 30/7, 2009 at 14:48 Comment(1)
Possible duplicate of C++: Pointer to monomorphic version of virtual member function?Stravinsky
B
13

When you call a virtual method via a reference or a pointer you will always activate the virtual call mechanism that finds the most derived type.

Your best bet is to add an alternative function that is not virtual.

Borak answered 30/7, 2009 at 17:26 Comment(0)
A
2

What you're trying to do unfortunately isn't possible. Pointer-to-member-functions are designed to maintain the virtualness of the function pointed-to.

Allfired answered 30/7, 2009 at 17:25 Comment(0)
R
1

Your problem is that a member function pointer is not quite the same as a bare function pointer. It actually isn't just a pointer, but a considerably more complex structure, which varies in its details at the level of the compiler implementation. When you invoke it via the syntax (this->*fp)() you are actually calling it on the original object, which causes virtual function dispatch.

One thing that might work is to cast it to a non-method pointer type. This is a little creaky but I think it should work. You still need to pass a Base * but you do it explicitly and the virtual function dispatch is by-passed:

typedef void BasePointer(Base*);

void callFunc()
{
    BasePointer fp = (BasePointer *)&Base::func;
    fp(this);
}

Update: Ok, no, you can't do it that way. It's illegal, and wouldn't be safe it if it was legal. The C++ FAQ has more on this. But knowing that doesn't solve your problem. The issue is that, pointer-to-object or pointer-to-member if you want to call Base::func through a Base pointer, the object it is pointing must also be a Base. If you can arrange that, then you can use a member function pointer.

Here's another thought, not pretty, but at least workable. Provide a function in Derived, non-virtual, that explicitly calls Base::func. Point to that instead. It won't scale if you need to do this in the general case of lots of different variants of func and callFunc but it will work fine for one method.

Resor answered 30/7, 2009 at 15:35 Comment(8)
That will most definitely not work! Compare sizeof(&Base::func) with sizeof(BasePointer) :oAllfired
mmutz: Yup. I try to always test before I post, and today I didn't leave myself the time to do it. It was possible a static_cast could be smart enough to pop the function pointer part out of the member function pointer, but I'm afraid my Python notion of a function is now overriding my C++ :).Resor
This is false: "it carries with it not just the address of the function to call but also the object to call it on"Shealy
Eric: Could you point me at some documentation on that? My understanding is that a member function pointer is specifically the pairing of a function pointer with a member pointer. That's why sizeof(&Base::func) is twice that of a normal pointer on every compiler I've tried.Resor
@quark: What would be the "object" in "&Base::func"? "Base" is a type, not an instance. Also notice that an instance must be provided when the pointer is used. (For example: BasePointer fp = &Base::func; Base b; b.*fp();).Shealy
@quark: About the "sizeof" part: On my current system (Windows XP, MSVC 7.1) sizeof(void*) == sizeof(function_pointer) == sizeof(member_function_pointer) == 4Shealy
Eric: Interesting. Your point about needing to provide the instance anyway is an obvious error on my part. It took some digging to find an actual explanation of what pointer-to-member-function actually is. Amending the answer. Thanks for the details.Resor
On VC++, sizeof() method pointer can actually vary depending on whether the method is virtual or not, and whether the class definition is in scope or not.Goeger
O
0

Is there any specific reason for doing this via a function pointer?

You should be able to just write:

Base::func();

to call the base class implementation.

Odiliaodille answered 30/7, 2009 at 14:52 Comment(2)
As I wrote in my question I save the pointer in callFunc but use it to actually call func from another place in my program.Sestertium
For a virtual function this won't work. It will always do a vtable lookup and call the method on the derived class.Villarreal
P
0

In addition to what quark says, a more general remark is that you should use a signal/slot implementation rather than a bare function pointer. Boost has one, there's libsigc and a bunch of others.

Poussin answered 30/7, 2009 at 15:58 Comment(0)
D
0

What's wrong with this?

(Base(*this).*fp)();

Now if you're satisfied with that, it raises the question of why you're even using a function pointer in the first place. I think some more context might help.

Directoire answered 30/7, 2009 at 21:41 Comment(1)
This was already suggested by quark ( "...if you want to call Base::func through a Base pointer, the object it is pointing must also be a Base." ). I'm assuming that Eddie can't guarantee that he knows the type to slice to when calling the function.Trail

© 2022 - 2024 — McMap. All rights reserved.