Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qualified-id call to base function via pointer

If I have a virtual function foo() first defined in a base class B and then overridden in a derived class D, how can I store the address of B::foo in a pointer-to-member-function in a way such that when calling it, the call would behave as a qualified-id call (like pd->B::foo())?

Example:

struct B {
    virtual int foo() { return 1; }
};

struct D: public B {
    virtual int foo() { return 2; }
};

int main(int argc, char * argv[]) {
    D* pd = new D();
    int (B::*pf)() = &B::foo;
    int r = (pd->*pf)();
    return 0; 
}

This would call D::foo(). Can I initialize pf in a way such that the (pd->*pf)() would call B::foo() even if pd's dynamic type is a class that overrides foo()?

(Before anyone asks, I don't really want to do this, I'm just curious if it's possible.)

like image 638
imre Avatar asked Dec 10 '14 09:12

imre


People also ask

Can we call base class function using derived class object?

Using a qualified-id to call a base class' function works irrespectively of what happens to that function in the derived class - it can be hidden, it can be overridden, it can be made private (by using a using-declaration), you're directly accessing the base class' function when using a qualified-id.

What should be used to call the base class method from derived class?

The base keyword is used to access members of the base class from within a derived class: Call a method on the base class that has been overridden by another method.

Can you call a virtual function from a destructor?

Similarly, it is permissible to call a virtual function from a constructor or destructor of a class that has the final class-virt-specifier, as in this example.


2 Answers

I don't believe you can.
I don't have my standard with me, but using the vararg hack to print the values of the pointer to member functions http://ideone.com/bRk7mG:

#include <iostream>
#include <cstdarg>
using namespace std;

struct Test
{
    void foo() {};
    virtual void bar() {}; 
    virtual void bar2() {};
    virtual void bar3() {};
};

void print_hack(int dummy, ...)
{
    va_list argp;
    va_start(argp, dummy);
    long val = va_arg(argp, long);
    cout << val << endl;
    va_end(argp);
}

int main() {
    print_hack (0, &Test::foo);
    print_hack (0, &Test::bar);
    print_hack (0, &Test::bar2);
    print_hack (0, &Test::bar3);
    return 0;
}

It seems like the value stored in the pointer (at least for GCC) is the index in the objects virtual table.
For non-virtual functions it seems like a regular function pointer.

Basically you are forced to do dynamic dispatch when using a pointer-to-member-function that holds a virtual function, at least as far as I know.

like image 192
StoryTeller - Unslander Monica Avatar answered Sep 26 '22 03:09

StoryTeller - Unslander Monica


I agree with StoryTeller, I don't think it is possible in any standard-compliant way. If what you really want to achieve is to be able to call either the base class implementation or derived class implementation using the same function pointer, the best I can recommend is this:

struct B {
    virtual int foo() { return fooB(); }
    int fooB() { return 1; }
};

struct D: public B {
    virtual int foo() { return 2; }
};

int main(int argc, char * argv[]) {
    D* pd = new D();
    int (B::*pf)() = &B::fooB;
    int r = (pd->*pf)();
    return 0; 
}

Since the function pointer type is the same whether a function is virtual or not, then creating a non-virtual function in the base class allows you to take its address directly.

like image 32
Vincent Zalzal Avatar answered Sep 25 '22 03:09

Vincent Zalzal