views:

266

answers:

2

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”;
    }
};
+4  A: 

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.)

Roger Pate
unfortunately there are many intermediate classes between the base class and the classes which may implement either new or old method. I was hoping to use this as a way to change as little code as possible, but that is looking less likely now.
intepid
A: 

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.

sharptooth
Why would you have a non-virtual method that derived classes must override? And if it is virtual but not pure, what advantage does this have over making it pure instead?
Roger Pate
In some cases you might need several kinds of derived classes. For classes belonging to a certain kind only a subset of methods will be called. That certainly sounds like inperfect OO design but you sometimes need this in real life.
sharptooth
My question comes from a need to support a mapping between two different interface methods, one new and one legacy. If the method had not been overridden it would mean it is safe to try mapping the call to the other method instead.Some objects implement new method and others don't, and similarly some calling code would call new and some legacy (messy I know, part of gradual refactoring). Without this ability it can only be mapped in one direction.
intepid
So use non-pure virtual methods in wrapping interface which call the legacy ones. If you override it and still need the legacy-call, explicitly call the base method in the override.
Georg Fritzsche
Had we used non-virtual wrapping methods from the start it would have been a piece of cake, but unfortunately these methods are overridden at several locations in a rather large class hierarchy.
intepid