I realize why calling an online function from the constructor isn't good, but I am unsure why determining a destructor would create a "pure virtual method known as" exception. The code uses const values to lessen using dynamic allocation - possibly even the reason.

#include <iostream>
using namespace std;

class ActionBase {
    ~ActionBase() { } // Comment out and works as expected

    virtual void invoke() const = 0;

template <class T>
class Action : public ActionBase {
    Action( T& target, void (T::*action)())
     : _target( target ), _action( action ) { }

    virtual void invoke() const {
        if (_action) (_target.*_action)();

    T&   _target;
    void (T::*_action)();

class View {
    void foo() { cout << "here" << endl; }

class Button : public View {
    Button( const ActionBase& action )
     : _action( action ) { }

    virtual void mouseDown() {

    const ActionBase& _action;

int main( int argc, char* argv[] )
    View view;
    Button button = Button( Action<View>( view, &View::foo ) );

    return 0;

You've Undefined Behavior. Because the parameter to Button's ctor is really a const&lifier from the temporary, it's destroyed in the finish of this line, immediately after the ctor finishes. You use later _action, after Action's dtor has run. As this is UB, the implementation is permitted to allow anything happen, and apparently your implementation happens to behave slightly different based on whether you've got a trivial dtor in ActionBase or otherwise. You receive the "pure virtual known as" message since the implementation is supplying behavior for calling ActionBase::invoke directly, that is what goes on once the implementation changes the object's vtable pointer in Action's dtor.

I suggest using boost.function or perhaps a similar 'action callback' library (boost has signals and signals2, for instance).

Set a breakpoint around the destructor and it'll become obvious what's happening. Yup, you're passing a brief demonstration of Action<> towards the Button constructor. It's destroyed following the button construct runs. Write it such as this and also the problem vanishes:

View view;
Action<View> event(view, &View::foo);
Button button = Button( event ); 

Well, that isn't an operating solution, event won't maintain scope for any real mouseDown invocation. The Button constructor will have to produce a copy from the "event" argument or it will need to run a pointer towards the delegate.

A category with virtual functions must always possess a virtual destructor, so ~ActionBase() ought to be virtual, (and thus should ~Action()). Should you switch on more compiler warning you're going to get an alert relating to this.

Basically, due to the research rules, the destructor is known as for any type the compiler knows can't be instantiated (pure virtual), therefore it knows something should have gone wrong.

I am sure another person can explain much better than I'm able to :)