CDT501 Chap.7 Classes, Inheritance and Composition
Classes, Inheritance and Composition
Trace ownership through every dot
This chapter binds self to one concrete receiver and separates class definitions from independent instances. It then contrasts inheritance as an is-a relationship with composition as a has-a relationship, traces method lookup and overriding, and diagnoses missing parent initialisation. Relationship diagrams are tested through the interface each arrow promises.
What this chapter covers
- 01
Classes and independent instances
- 02
Self and instance attributes
- 03
Method calls and returned values
- 04
Inheritance and parent initialisation
- 05
Composition and object ownership
Worked example · free
Repair state that never reached the object
- 2Bind self to the receiving object.
- 2Locate persistent instance state.
- 2Test a second object's independence.
Key terms
- Class
- A definition describing how to construct and operate a kind of object.
- Self
- The parameter referring to the particular object receiving an instance method call.
- Attribute
- A named piece of state stored on an object or class.
- Method
- A function reached through an object or class namespace.
- Parent Class
- A class whose interface and implementation a child class may inherit.
- Method Override
- A child-class definition replacing inherited behaviour under the same method name.
Classes, Inheritance and Composition FAQ
Why do two instances keep different values?
Each construction creates a separate object and its instance attributes belong to that object. The objects share method definitions through the class but not ordinary per-instance state. A change through one receiver therefore remains on that receiver unless both objects deliberately reference another shared mutable object.
When should I use inheritance rather than composition?
Use inheritance when the child genuinely is a specialised form of the parent and can support the promised parent interface. Use composition when an object has or collaborates with another object. Reusing code is not enough to justify a subtype relationship if the domain sentence is false.
Why is a parent attribute missing from a child object?
When the child defines its own constructor, the parent's constructor does not automatically create the parent state. Call the parent initialiser, commonly through super, when inherited methods still depend on those attributes. Repair construction rather than adding fallbacks where the missing attribute is eventually used.
How can I tell that a class has too many responsibilities?
Look for groups of attributes and methods that change for unrelated reasons. A class that validates student records, formats reports, reads files and sends network requests has several distinct causes of change and is difficult to test in isolation. Name the invariant each group protects and the collaborators it needs.
If one subset can be described without mentioning the rest, extract it into a focused class or function and connect the pieces through composition. Do not split purely to reduce line count: closely related state and behaviour should remain together. The useful boundary is conceptual ownership, revealed by independent rules, independent tests and dependencies that only part of the original class requires.
Assessment move
Create two objects from one class and trace an update to only one of them. For every method call, write the receiver bound to self and distinguish local names from instance attributes. Draw inheritance vertically and composition horizontally, then test one operation along each arrow. Deliberately omit a parent constructor call and explain the later attribute failure from its real cause.
Begin by listing the attributes promised immediately after construction. Instantiate two objects with clearly different values and inspect both before and after one method call. If both change, investigate class attributes or a shared mutable collaborator; if neither changes, check whether the method updated a local name instead of self state.
Rewrite one print-only method to return text and let the caller display it, then assign the result during a test to confirm the interface. For inheritance, complete the sentence “every child is a parent” and reject the hierarchy if substitution sounds false. Call a method present only on the parent through a child instance to demonstrate upward lookup, then override it and compare results from parent and child objects.
Define a child constructor without the parent call, inspect the incomplete object and repair it with super before exercising inherited behaviour. For composition, attach a collaborator object and trace an access such as owner.component.attribute. Explain which object owns each piece of state and why the parent should not receive subtype-specific data.
Import the classes from a module in two styles and note how the namespace communicates origin. Finish with a responsibility statement and one invariant for every class. Test the invariant after construction and mutation, and add a deliberately invalid call that the interface should reject. Successful demonstrations show capability; rejected operations reveal whether the relationship model is honest.
Working through Classes, Inheritance and Composition in CDT501? Sia is AskSia’s AI Computer Science tutor — ask any CDT501 Classes, Inheritance and Composition question and get a clear, step-by-step explanation grounded in how CDT501 is taught and assessed. Read this chapter free, then take your hardest questions to Sia.