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.
Example, bad
class B { // BAD: polymorphic base class doesn't suppress copying
public:
virtual char m() { return 'B'; }
// ... nothing about copy operations, so uses default ...
};
class D : public B {
public:
char m() override { return 'D'; }
// ...
};
void f(B& b)
{
auto b2 = b; // oops, slices the object; b2.m() will return 'B'
}
D d;
f(d);
Example
class B { // GOOD: polymorphic class suppresses copying
public:
B() = default;
B(const B&) = delete;
B& operator=(const B&) = delete;
virtual char m() { return 'B'; }
// ...
};
class D : public B {
public:
char m() override { return 'D'; }
// ...
};
void f(B& b)
{
auto b2 = b; // ok, compiler will detect inadvertent copying, and protest
}
D d;
f(d);
Note
If you need to create deep copies of polymorphic objects, use clone() functions: see C.130.
Exception
Classes that represent exception objects need both to be polymorphic and copy-constructible.
Enforcement
- Flag a polymorphic class with a public copy operation.
- Flag an assignment of polymorphic class objects.
C.other: Other default operation rules
In addition to the operations for which the language offers default implementations, there are a few operations that are so foundational that specific rules for their definition are needed: comparisons, swap, and hash.