The sample method below is intended to detec开发者_JS百科t 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”;
}
};
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.)
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.
精彩评论