A common mistake is treating polymorphic bases like ordinary value types. Public copy and move operations can cause slicing, where the dynamic type information is lost during copying. In practice, such bases usually need a virtual destructor, deleted copy and move operations, or cloning through virtual methods instead of direct value semantics.
Why polymorphic base classes should not behave like value types
Polymorphic bases are meant to support runtime dispatch, not ordinary copying. If you let them behave like plain values, you invite slicing, where only the base subobject is copied and the derived part disappears. That breaks substitutability in practice because the copied object no longer preserves the dynamic type or the behaviour that made the base polymorphic in the first place.
Once a base class has virtual behaviour, the design question changes from “can I copy it?” to “what does copying mean for this hierarchy?” In many cases, the right answer is that copying should be forbidden, or it should be expressed through a virtual cloning operation that preserves the concrete type. Public value semantics and polymorphism often point in opposite directions.
Which special member functions usually cause the mistake?
The common trap is leaving copy and move operations public and compiler-generated by default. That makes the base look like a normal value type, even when it is really an interface-like anchor for derived objects. A virtual destructor is usually needed so deletion through a base pointer is safe, but the presence of that destructor does not by itself make copying safe or well-defined.
When a polymorphic base is not meant to be copied, the strongest signal is to delete copy and move construction and assignment explicitly. That forces consumers to hold the object by pointer or reference, or to use a clone function if ownership transfer of a duplicated dynamic type is genuinely needed. The key design point is consistency: the public operations should match the semantics the type can actually support.
Another mistake is assuming “rule of zero” still applies automatically. For a polymorphic base, the compiler may generate operations that are technically valid but semantically wrong for the intended use. You need to decide whether the base represents an interface, an owning type, or a clonable abstraction, and then make the special member functions reflect that choice.
What to do instead when the hierarchy needs copying
If copying a derived object is a real requirement, model it deliberately. A virtual clone-style design is often clearer than relying on copy construction through a base interface, because it preserves the dynamic type and makes ownership boundaries explicit. If copying is not part of the abstraction, delete the operations and avoid accidental slicing at the call site.
The best design also keeps object lifetime simple. A base with virtual functions and a virtual destructor usually wants non-owning references, smart pointers, or a separate value wrapper if callers need value-like behaviour. That separation lets the polymorphic core stay focused on dispatch while the wrapper, if needed, handles duplication and storage semantics.
Risk and Threat Considerations
Incorrect special member function design can create subtle integrity bugs rather than immediate crashes. Slicing can silently remove derived state, so an object may compile, copy, and run while no longer enforcing the behaviour the programmer expected.
Failure mechanism: Public copy or move operations on a polymorphic base allow the base subobject to be copied as if the type were a value, which discards derived-specific data and behaviour. Deletion through a non-virtual destructor, or copying through the wrong abstraction boundary, can then compound the defect into undefined behaviour or corrupted object state.
Impact: The result is a hierarchy that behaves differently under storage, return-by-value, or container use than it does under direct polymorphic use. In security-sensitive or correctness-sensitive code, that can invalidate invariants, hide state loss, or make a derived type appear to have been preserved when it has not.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
NIST SP 800-53 Rev 5 and OWASP ASVS set the technical controls, while ISO/IEC 27001:2022 defines the regulatory obligations.
| Framework | Control / Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev 5 | IA-2 — Identification and Authentication (Organizational Users) | Polymorphic object handling is an access-and-identity design analogue, where misuse of the base interface can misrepresent the actor or object state. |
| AC-6 — Least Privilege | Deleting unsafe copy and move operations limits unintended capabilities on a polymorphic base. | |
| Recommendation — Apply IA-2 discipline to ensure the interface preserves the intended subject identity and does not collapse distinct object roles. Restrict operations to the minimum the abstraction actually supports. | ||
| OWASP ASVS | V15 — Secure Coding and Architecture | The issue is a design-level C++ correctness pattern that requires explicit semantics for copying and lifetime. |
| Recommendation — Design polymorphic classes so special member functions match the object model they are meant to support. | ||
| ISO/IEC 27001:2022 | A.8.9 — Configuration management | The base-class API and special member function choices are part of secure, controlled design configuration. |
| Recommendation — Control the class interface so accidental copying and lifetime semantics cannot be introduced unnoticed. | ||
Practitioner Guidance
What to verify: Check whether the base is truly intended to be copied, moved, or only referenced. If the answer is “only referenced,” delete copy and move operations and ensure deletion through the base is safe with a virtual destructor.
Decision rule: If callers need duplication of the dynamic type, provide an explicit clone path; if they only need substitution, make the type non-copyable and keep ownership outside the polymorphic hierarchy. Do not rely on compiler-generated special members to express that decision for you.
Common mistake: Treating a polymorphic base like a container-friendly value type and discovering slicing only after the hierarchy has already been used in return-by-value, assignment, or generic code.
Practitioner takeaway: The safest default is to make the base class semantics unmistakable, either non-copyable, or clonable with explicit dynamic-type preservation, but not ambiguously both.
Related resources from NHI Mgmt Group
- What do teams get wrong about novel crypto asset classes?
- What do security teams get wrong about base image trust?
- What do teams get wrong about Features and Special Feature 2 in TCF 2.4?
- What do teams get wrong about certificate management when collaboration is spread across many users and functions?
Deepen Your Knowledge
Reviewed and updated by the NHIMG editorial team on September 25, 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org