views:

1157

answers:

6

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.

+1  A: 

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.

Timo Geusch
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.
+1  A: 

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.

quark
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++ :).
quark
This is false: "it carries with it not just the address of the function to call but also the object to call it on"
Éric Malenfant
quark
@quark: What would be the "object" in " Base b; b.*fp();).
Éric Malenfant
@quark: About the "sizeof" part: On my current system (Windows XP, MSVC 7.1) sizeof(void*) == sizeof(function_pointer) == sizeof(member_function_pointer) == 4
Éric Malenfant
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.
quark
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.
Pavel Minaev
A: 

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.

Roel
+2  A: 

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.

+5  A: 

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 fundtion that is not virtual.

Martin York
A: 

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.

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.
Troubadour