Assume I want to suppress copying/moving in a base class, but allow it for a derived class. I can accomplish the functionality like this:
class Base {
public:
virtual ~Base() = default;
virtual bool magic() const;
protected:
Base() = default;
Base(const Base&) = default;
Base& operator=(const Base&) = default;
Base(Base&&) = default;
Base& operator=(Base&&) = default;
};
class Derived : public Base {
public:
Derived() = default;
Derived(int x, double y) : x_(x), y_(y) {};
bool magic() const;
private:
int x_;
double y_;
}
The "problem" is that this doesn't follow C.67 in the ISO C++ Core Guidelines: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-copy-virtual
C.67 states
C.67: A polymorphic class should suppress public copy/move
Reason A polymorphic class is a class that defines or inherits at least one virtual function. It is likely that it will be used as a base class for other derived classes with polymorphic behavior. If it is accidentally passed by value, with the implicitly generated copy constructor and assignment, we risk slicing: only the base portion of a derived object will be copied, and the polymorphic behavior will be corrupted. If the class has no data, =delete the copy/move functions. Otherwise, make them protected.
The way I interpret this is that I should delete my copy/move constructors/assignment operators in the base class, since it has no data members:
class Base {
public:
Base(const Base&) = delete;
Base& operator=(const Base&) = delete;
Base(Base&&) = delete;
Base& operator=(Base&&) = delete;
virtual ~Base() = default;
virtual bool magic() const;
protected:
Base() = default;
};
class Derived : public Base {
public:
Derived() = default;
Derived(int x, double y) : x_(x), y_(y) {};
Derived(const Derived& d) : Base(), x_(d.x_), y_(d.y_) {};
...
bool magic() const;
private:
int x_;
double y_;
}
But doing so, will force me to implement copy/move constructors/assignment operators in my derived class (which is a point with the guideline, I assume). I can come up with no other way than to manually copy all the data members of my derived class, which seems quite bloated. If I add a new data member and forget to update my copy/move functions, they will break.
Is there an easier way to define copy/move constructors/assignment operators in my derived class, when they are deleted in the base class? And what is the best practice in this situation?
EDIT:
As pointed out in the comments, the copy/move constructors/assignment operators should not be public in the derived class either, according to the same guideline. But the problem remains when defining them as protected.