C++ Inheritance: Fundamentals and Advanced Concepts
1. Inheritance Basics
(1) Concept
Objects abstract into classes, and subclasses generalize (or inherit from) parenet classes.
class BaseClass {
// Base members
};
class DerivedClass : public/protected/private BaseClass { // Inheritance type
// Derived members
};
(2) Derived Class Creation Process
- Absorb Base Members: A base sub-object is created to access the base's members (inheritance grants access, not duplication).
- Add New Members (optional).
- Hide Base Members (optional): If a derived class has a member with the same name as the base, the base's member is hidden.
Absorption effects:
- Inheritance Access: Derived classes can access base members (code reuse).
- Memory Sharing: Base members exist in the derived object's memory (part of the base sub-object).
(3) Access Permissions for Inheritance Types
Three inheritance types:
- Public Inheritance
- Protected Inheritance
- Private Inheritance: The "final" layer, but even private inheritance allows direct derived classes to access the base's
public/protectedmembers.
Default is private inheritance if not specified.
Private Inheritance Behavior:
In multi-level inheritance, if one layer uses private inheritance, lower layers cannot access higher base members (direct base's non-private members are still accessible).
Derived Class Access Summary:
- Derived classes can never access the base's
privatemembers internally. - Derived classes can access all base members except
privateones internally. - Externally, derived objects can only access
publicmembers of the base (from public inheritance).
(Memory Aid: 1. Private members are inaccessible externally. 2. Inheritance type intersects with base member access permissions.)
Q: Which base members can a derived object access?
A: public members of a public-inherited base.
(2) Inheritance Limitations (*)
- Creation/Destruction: Constructors/destructors are not inherited.
- Copy Control: Copy constructors/assignment operators are not inherited.
- Memory Allocation:
operator new/operator deleteare not inherited. - Friends: Friendships are not inherited (to preserve encapsulation).
Thus, the 6 compiler-provided functions and friends are not inheritable.
2. Single Inheritance: Object Creation/Destruction
(1) Simple Single Inheritance Structure
- If a derived class does not explicitly call a base constructor, the base's default (or parameterized with defaults) constructor is used.
The anonymous base sub-object is created.
-
If the base has no default constructor and the derived constructor does not explicitly call a base construcotr, the compiler errors (derived object creation is forbidden).
-
To use a non-default base constructor, explicitly call it in the derived constructor's initializer list.
Constructor Order: Base → Derived
Destructor Order: Derived → Base
(2) Derived Objects with Member Objects
-
Initialization Order:
- Constructor: Base sub-object → Member objects (in declaration order) → Derived
- Destructor: Derived → Member objects (reverse declaration order) → Base sub-object
-
Initialization Location:
Member objects are initialized in the initializer list:memberObject(parameters).
3. Multiple Inheritance
(0) Concept
A class inherits from multiple base classes. The diamond inheritance occurs when a class indirectly inherits the same base via two paths, causing data redundancy and ambiguity.
Virtual inheritance resolves this by ensuring a single instance of the shared base.
(1) Multiple Inheritance: Construction/Destruction
class D : public A, B, C { // Defaults to private for B/C
// D members
};
// To publicly inherit A, B, C:
class D : public A, public B, public C {
// D members
};
- Construction Order: Follows the inheritance declaratino order (A → B → C → D).
- Destruction Order: Reverse of construction (D → C → B → A).
(2) Multiple Inheritance Issues
① Member Access Ambiguity
If a derived class has no print() but multiple bases do, the compiler cannot determine which base to use (ambiguity).
Solutions:
- Add class scope (not recommended).
- Hide via a derived class
print()(hides base versions).
② Storage Ambiguity (Diamond Inheritance)
The derived class contains multiple base sub-objects (from the diamond structure), causing ambiguity.
Solution: Use virtual inheritance in intermediate bases to share a single base instance.
class A { // Top-level base
public:
void print() const { /* ... */ }
double a;
};
class B : virtual public A { // Virtual inheritance
public:
double b;
};
class C : virtual public A { // Virtual inheritance
public:
double c;
};
class D : public B, public C {
public:
double d;
};
- Virtual Inheritance Memory Layout:
Intermediate classes (B, C) contain a virtual base pointer to the shared A sub-object. The final derived class (D) has only one A sub-object.
4. Base-Derived Class Conversions
(1) Upcasting (Derived → Base)
Allowed implicitly.
- Object Assignment:
Base b = Derived(); - Pointer Assignment:
Base* ptr = new Derived(); - Reference Binding:
Base& ref = Derived();
(2) Downcasting (Base → Derived)
Not allowed implicitly, but safe with dynamic_cast (for polymorphic types).
5. Derived Class Copy Control
Explicitly call base copy control functions in derived ones.
- Copy Constructor:
Derived::Derived(const Derived& d) : Base(d) { /* ... */ } - Assignment Operator:
Derived& operator=(const Derived& d) { Base::operator=(d); /* ... */ return *this; }
Rule:
- If no derived copy control is defined, base copy control is auto-invoked.
- If derived copy control is defined, base copy control must be explicitly called.