With regard to 1 ("a default destructor"), it's simply because memcpy
of a new object into an existing variable won't call the destructor of what it's overwriting, so if the class depends on anything in that destructor, its constraints may be violated.
With regard to 2 ("no virtual functions"), it's likely that the reasoning is that when object slicing occurs, the sliced object must function correctly as the base class object.
Imagine a base and a derived class thus:
class Base {
int b;
virtual void f() { ++b; }
}
class Derived : public Base {
int d;
void f() override { ++d; }
}
Now suppose you have a Base&
variable v
that actually references a Derived
object. If std::is_trivially_copyable<Base>
were true, you could memcpy
from this variable to another Base
object w
(this would copy b
and the vtable
). If you were now to call w.f()
, you would call (through the vtable) Derived::f()
. Which of course would be undefined, as w.d
has no storage allocated.
This may account also for 3 ("no virtual base classes"), but since I pretty much never use virtual base classes, I'll defer to someone more familiar with them.