6

I have a base class Base and a derived class D, and I'd like to have move constructor and move assignment operator automatically generated by the compiler for me. Following the Rule of Zero, I leave all memory management to the compiler and only use level-2 classes (no raw pointers, arrays, etc.):

#include <iostream>

class Base{
  public:
    Base(): a_(42) {}
    virtual void show() { std::cout << "Base " << a_ << std::endl; }

  private:
    int a_;
};

class D : Base {
  public:
    D(): b_(666) {}
    void show() { std::cout << "D " << b_ << std::endl; }

  private:
    int b_;
};

int main() {
  Base b;
  b.show();
  D d;
  d.show();
  return 0;
}

This should be it, right?

Enter the C++ core guidelines:

A base class destructor should be either public and virtual, or protected and nonvirtual.

Ah, so I guess I'll have to add a destructor to Base. But that'll do away with the automatically generated move functions!

What's the clean way out here?

Nico Schlömer
  • 53,797
  • 27
  • 201
  • 249
  • 4
    You can `= default` the destructor, and declare it public virtual or protected, as you see fit. – king_nak Jan 02 '17 at 10:27
  • Strongly related: [Why does destructor disable generation of implicit move methods?](http://stackoverflow.com/q/33932824/514235) – iammilind Jan 02 '17 at 10:38

2 Answers2

8

You can = default everything that you would like to be generated by the compiler. See (at the bottom): http://en.cppreference.com/w/cpp/language/rule_of_three

In your case it could look something like:

class Base{
  public:
    Base(): a_(42) {}
    Base(const Base&) = default;
    Base(Base&&) = default;
    Base& operator=(const Base&) = default;
    Base& operator=(Base&&) = default;
    virtual ~Base() = default;

    virtual void show() { std::cout << "Base " << a_ << std::endl; }

  private:
    int a_;
};
AMA
  • 4,114
  • 18
  • 32
2

You can create once a class like

struct VirtualBase
{
      virtual ~VirtualBase() = default;
      VirtualBase() = default;
      VirtualBase(const VirtualBase&) = default;
      VirtualBase(VirtualBase&&) = default;
      VirtualBase& operator = (const VirtualBase&) = default;
      VirtualBase& operator = (VirtualBase&&) = default;
};

And then follow rule of zero:

class Base : VirtualBase
{
public:
    Base(): a_(42) {}
    virtual void show() { std::cout << "Base " << a_ << std::endl; }

  private:
    int a_;
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Nice suggestion & I was about to write this answer. But wasn't sure, what will be its fate when there is multiple inheritance involved. Isn't it safe to inherit `VirtualBase` virtually? – iammilind Jan 02 '17 at 10:40
  • @iammilind: virtual inheritance has a higher cost than simple inheritance, so unless needed, I will stick with normal inheritance. – Jarod42 Jan 02 '17 at 10:43
  • @iammilind it is safe to inherit either virtually or not. – n. m. could be an AI Jan 02 '17 at 11:02