Does a default virtual destructor prevent compiler-generated move operations?

Yes, declaring any destructor will prevent the implicit-declaration of the move constructor.

N3337 [class.copy]/9: If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

  • X does not have a user-declared copy constructor,
  • X does not have a user-declared copy assignment operator,
  • X does not have a user-declared move assignment operator,
  • X does not have a user-declared destructor, and
  • the move constructor would not be implicitly defined as deleted.

Declaring the destructor and defining it as default counts as user-declared.

You'll need to declare the move constructor and define it as default yourself:

WidgetBase(WidgetBase&&) = default;

Note that this will in turn define the copy constructor as delete, so you'll need to default that one too:

WidgetBase(const WidgetBase&) = default;

The rules for copy and move assignment operators are pretty similar as well, so you'll have to default them if you want them.