6

I need to call the base method A::foo() from derived class by pointer.

#include <iostream>
struct A{
    virtual void foo() { std::cout << "A::foo()" << std::endl; }
};

struct B:A{
    virtual void foo() { std::cout << "B::foo()" << std::endl; }
    void callBase(void (A::*f)()){
        (this->*f)();
    }
};

int main(){
    B* p=new B();
    p->callBase(&A::foo);
}

This code output "B::foo". Is it possible to call A::foo() by pointer to method?

5
  • I don't think you can. However, I have been wrong in the past :) Let's hope someone more knowledgeable than me knows a way. Commented Dec 26, 2017 at 7:16
  • 1
    You can call it directly like p->A::foo(); but not through a pointer to member function (which I guess is the point of virtual functions). Commented Dec 26, 2017 at 7:20
  • I believe you work around this by having a non-virtual bar that does the work, and have foo delegate to bar, callBase then calls bar. This is more logical since polymorphism means B should always call its own foo Commented Dec 26, 2017 at 7:39
  • @PasserBy I just don't understand: I can explicitly specify class in hierarchy which method should be called like A::foo(). Here I do similar thing &A::foo. Virtual methods probably have different pointers. I guess this stupid assymetric behaviour related with vtable implementation. Commented Dec 26, 2017 at 15:04
  • @EgorDudyak This isn't "stupid assymetric behaviour", it is doing exactly what was intended, aka polymorphism. Consider A* a = new B; auto p = &A::foo; (a->*p)(); Commented Dec 26, 2017 at 23:59

2 Answers 2

1

Well, you can do something similar using some tricks with overwriting the value of this. You probably should never try to do that though, vtable pointers aren't meant to be modified by hand.

To do what you described, we need to have the pointer to A's vtable. Our object p has only pointer to B's vtable, so we need to store second pointer in a field within A's constructor.

Here is the code:

#include <iostream>
struct A{
    virtual void foo() { std::cout << "A::foo()" << std::endl; }
    int *a_vtable_ptr;
    // First, save value of A's vtable pointer in a separate variable.
    A() { a_vtable_ptr = *(int**)this; }
};

struct B:A{
    virtual void foo() { std::cout << "B::foo()" << std::endl; }
    void callBase(void (A::*f)()){
        int *my_vtable_ptr = *(int**)this;
        // Then modify vtable pointer of given object to one that corresponds to class A.
        *(int**)this = a_vtable_ptr;
        (this->*f)(); // Call the method as usual.
        // Restore the original vtable pointer.
        *(int**)this = my_vtable_ptr;
    }
};

// Function main() is not modified.
int main(){
    B* p=new B();
    void (A::*f)() = &A::foo;
    p->callBase(f);
}

Output:

A::foo()

Process finished with exit code 0
Sign up to request clarification or add additional context in comments.

Comments

1

Virtual methods are designed to implement polymorphism and pointers to virtual methods supports their polymorphic behavior. But you given the possibility to call the base method by explicitly calling p->A::foo().

So if you want to call base method by pointer, you should make it non-virtual (as @PasserBy mentioned in comments).

Code example:

struct A {
    virtual void foo() { std::cout << "A::foo()" << std::endl; }
    void bar() { std::cout << "A::bar()" << std::endl; }
    void callBase(void (A::*f)()) { (this->*f)(); }
};

struct B : A {
    virtual void foo() { std::cout << "B::foo()" << std::endl; }
    void bar() { std::cout << "B::bar()" << std::endl; }
};

int main()
{
    A* p = new B();
    p->foo();
    p->bar();
    p->callBase(&A::foo);
    p->callBase(&A::bar);
    p->A::foo();
    p->A::bar();
}

Output:

B::foo()
A::bar()
B::foo()
A::bar()
A::foo()
A::bar()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.