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.)
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With