Question

The sample method below is intended to detect whether or not it has been overridden in a derived class. The error I get from MSVC implies that it is simply wrong to try to get the function pointer to a "bound" member, but I see no logical reason why this should be a problem (after all, it will be in this->vtable). Is there any non-hacky way of fixing this code?

class MyClass
{
public:
    typedef void (MyClass::*MethodPtr)();  

    virtual void Method()
    {
        MethodPtr a = &MyClass::Method; // legal
        MethodPtr b = &Method;  // <<< error C2276: ‘&’ : illegal operation on bound member function expression

        if (a == b)     // this method has not been overridden?
            throw “Not overridden”;
    }
};
Was it helpful?

Solution

There is no way to determine if a method has been overridden, except for pure virtual methods: they must be overridden and non-pure in a derived class. (Otherwise you can't instantiate an object, as the type is still "abstract".)

struct A {
  virtual ~A() {} // abstract bases should have a virtual dtor
  virtual void f() = 0; // must be overridden
}

You can still provide a definition of the pure virtual method, if derived classes may or must call it:

void A::f() {}

Per your comment, "If the method had not been overridden it would mean it is safe to try mapping the call to the other method instead."

struct Base {
  void method() {
    do_method();
  }

private:
  virtual void do_method() {
    call_legacy_method_instead();
  }
};

struct Legacy : Base {
};

struct NonLegacy : Base {
private:
  virtual void do_method() {
    my_own_thing();
  }
};

Now, any derived class may provide their own behavior, or the legacy will be used as a fallback if they don't. The do_method virtual is private because derived classes must not call it. (NonLegacy may make it protected or public as appropriate, but defaulting to the same accessibility as its base class is a good idea.)

OTHER TIPS

You can actually find this out. We encountered the same problem and we found a hack to do this.

#include<iostream>
#include<cstdio>
#include<stdint.h>

using namespace std;

class A {
public:
    virtual void hi(int i) {}
    virtual void an(int i) {}
};

class B : public A {
public:
    void hi(int i) {
        cout << i << " Hello World!" << endl;
    }
};

We have two classes A and B and B uses A as base class.

The following functions can be used to test if the B has overridden something in A

int function_address(void *obj, int n) {
    int *vptr = *(int **)&obj;
    uintptr_t vtbl = (uintptr_t)*vptr;

    // It should be 8 for 64-bit, 4 for 32-bit 
    for (int i=0; i<n; i++) vtbl+=8;

    uintptr_t p = (uintptr_t) vtbl;
    return *reinterpret_cast<int*>(p);
}

bool overridden(void *base, void* super, int n) {
    return (function_address(super, n) != function_address(base, n));
}

The int n is the number given to method as they are stored in vtable. Generally, it's the order you define the methods.

int main() {
    A *a = new A();
    A *b = new B();

    for (int i=0; i<2; i++) {
        if (overridden(a, b, i)) {
            cout << "Function " << i << " is overridden" << endl;
        }
    }

    return 0;
}

The output will be

Function 0 is overridden

EDIT: We get the pointers to vtables for each class instance and then compare the pointer to the methods. Whenever a function is overridden, there will be a different value for super object.

There's no portable way of doing that. If your intention is to have a method that is not pure virtual, but needs to be overridden for every class it will be called on you can just insert an assert( false ) statement into the base class method implementation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top