1.2 OOP by Example

Object-oriented Programming (OOP) is a method of software development centred around objects and classes. Unlike traditional procedural programming, which keeps data and behaviour separate, OOP organises software as a set of interacting objects that encapsulate both data and the actions that can be performed on that data. This object-based approach provides a way to structure and manage complex software systems.
Object-oriented programming is a cornerstone of software development. Emerging in the 1980s, the concept of objects gained traction in programming languages. By the 1990s, nearly all new languages incorporated object-oriented features, and even existing languages were adapted to include them. Today, object-oriented programming is largely considered one of the most significant and effective approaches to software creation.
The object-oriented programming paradigm encourages:
- Modularity: The decomposition of software applications into discrete and self-contained modules, facilitating organisation and reducing complexity.
- Software Reusability: The development of applications through the incorporation of existing, well-tested modules alongside newly created components, promoting efficiency and reducing development time.
Object-oriented programming languages generally support the following main features:
- Classes and Objects: Fundamental building blocks of OOP, where classes define blueprints for creating objects, which are instances of those classes.
- Encapsulation: Bundling data (attributes) and methods (functions) that operate on the data into a single unit, controlling access to the internal state of an object.
- Inheritance: A mechanism that allows a new class (derived or child class) to inherit properties and behaviours from an existing class (base or parent class), promoting code reusability.
- Polymorphism: The ability of a single interface to represent different underlying forms (data types or classes), enabling methods to operate on objects of various classes through a common interface.
- Abstraction: Simplifying complex systems by modelling classes based on essential characteristics while hiding unnecessary implementation details, focusing on what an object does rather than how it does it.
The sections that follow give examples of each of these features.
A Class
Section titled “A Class”A Class is a Description. If we think of a real-world object, such as a television (as illustrated in Figure 1), it has several characteristics and properties:
- We do not have to open the physical case to use it.
- We have some form of controls to use it (buttons on the case, or a remote control).
- We can still understand the concept of a television, even if it is connected to a games console.
- It is complete when we purchase it, with any external requirements well documented.
- The TV should not crash!

In many ways the television provides a good analogy for the concept of a class. For example, a class should:
- Provide a well-defined interface such as the remote control of the television.
- Represent a clear concept such as the concept of a television.
- Be complete and well-described. The television should have a plug, internet connection inputs and should have a manual that documents all features.
- Should be robust. Similar to the television, the code should not fail regardless of what functions the user calls, and the order in which they are called.
If we were to implement a television with a purely procedural programming language (like C) we would typically have the component parts of the television separated out and we would be responsible for connecting them and making them work together. To continue the analogy, there would certainly be no case surrounding the different electronic components, as illustrated in Figure 1.
Classes provide a mechanism for representing complex data structures within a programming language. They comprise two defining characteristics:
- States (also referred to as attributes or data) represent the values held by the object.
- Methods (also known as functions or behaviours) delineate the object’s interactions with its data and the actions it can perform.
The notation used in Figure 2 on the right-hand side is a Unified Modelling Language (UML) representation of the Television class.

An Object
Section titled “An Object”A class is a description and an object is a realisation of this description — i.e., an object is an instance of a class.
A class may be conceived as the formal specification of a concept, while an object represents the instantiation of that specification into a discrete, identifiable entity. For instance, with respect to a television, the class constitutes the set of schematics or blueprints for a generic television, whereas a television object is the physical manifestation of these schematics into a ‘real-world’ television unit. Consequently, a single set of schematics (the class) exists, but many physical television units (objects) can be produced.
Objects may manifest as real-world entities (such as physical items or digital files) or as abstract constructs (such as database schemas), each possessing a unique identity. As illustrated in Figure 4, the Television class archetype can be instantiated into multiple distinct television objects. These objects are characterised by their individual identities and operational independence. Notably, modifications to a state (such as changing the channel) on a particular television, do not propagate to other objects of the same class — i.e., they each have individual and independent states (just as they would in the real world).

Encapsulation
Section titled “Encapsulation”The object-oriented paradigm promotes encapsulation, which involves hiding the internal workings of an object. This allows the implementation details to be concealed, meaning we do not need to understand how the object operates internally — only how to interact with it through its defined interface.
A good analogy is the Television class. The complex internal functionality of the television (such as decoding a signal from the aerial and rendering an image on the screen) is hidden from the user. Instead, we interact with the television via a remote control or a set of buttons, which serves as a high-level interface. As illustrated in Figure 5, there is no need to understand how the signal processing works in order to use the television.
Only a specific subset of the class’s functionality is exposed to the user — this is known as the interface. In the case of the television, this includes the features accessible via the remote control or the buttons on the device itself.
The full implementation of a class comprises both the public interface and the private implementation, encapsulating behaviour while maintaining ease of use and abstraction.

Encapsulation refers to the separation of an object’s interface from its implementation. It is often described as data hiding, allowing certain aspects of an object to be visible while keeping others hidden. This approach offers clear benefits to both users (who may be other programmers) and developers.
For the user of the code (usually also a programmer):
- The user only needs to understand the interface.
- The user does not need to know how the implementation works or how it was developed.
For the developer of the code:
- The implementation can be changed without needing to inform the user.
- As long as the interface remains unchanged, the user remains unaware of internal modifications — aside from any subtle changes in the system’s behaviour.
Encapsulation is typically implemented using access modifier keywords such as public, private, and protected:
- Public methods define the interface — the parts of the class accessible to users.
- Private methods form the internal implementation — hidden from the user.
Figure 6 illustrates encapsulation in the context of the Television class. According to UML notation, private methods are marked with a minus sign (−), and public methods with a plus sign (+). For example, a user may call the public powerOn() method, but this might internally trigger a private displayPicture() method. The user does not call displayPicture() directly, and it is not part of the interface. Instead, it is hidden within the implementation using the private access modifier.

public and private access specifiers.
🧩Knowledge Check
Section titled “🧩Knowledge Check”Which of the following are core benefits provided by the object-oriented programming paradigm?
What is the primary difference between a Class and an Object?
Regarding Encapsulation, which statements accurately describe its implementation and benefits?
Inheritance
Section titled “Inheritance”When we have several descriptions that share common features, we can use inheritance to group these descriptions and their shared characteristics into a more compact and efficient representation. Object-oriented programming supports this by allowing us to define a base class containing the commonalities, and then create derived classes that specify the differences.
The Duck
Section titled “The Duck”
Humans naturally use the concept of classification when categorising objects and descriptions. For example, if asked “What is a duck?”, you might reply “a bird that swims”, or more precisely, “a bird that swims, with webbed feet and a bill instead of a beak.” In this case, we can describe a Duck as a Bird that swims — illustrating an inheritance relationship, as shown in Figure 8. Essentially, a Duck is a specialised type of Bird.
However, it is important to note that we also specified two distinct differences:
- “With webbed feet” introduces a new feature — webbing added to the feet.
- “With a bill instead of a beak” indicates a modification or replacement — removing the beak from the base class and adding a bill in the derived class.
This distinction is explored further using vehicles as an example below. For now, it is worth noting that this kind of variation allows the base class to loosely define common characteristics, without requiring an exact match to all properties found in its derived classes.

A Vehicle Example
Section titled “A Vehicle Example”For example, if we were given an unstructured list of descriptions such as Car, Saloon, Estate, Van, Vehicle, Motorbike, and Scooter, and asked to organise them based on their differences, we might proceed as follows: a Saloon car is a type of Car that has a long boot, while an Estate car is a type of Car with a very large boot. Figure 9 illustrates how these descriptions can be organised using inheritance.

We can describe this as a parent/child relationship, where the connection between a base (parent) class and the derived (child) class. A derived class inherits from a base class; for example, in Figure 9, the Car class is a child of the Vehicle class, meaning that Car inherits from Vehicle.
Is Your Inheritance Hierarchy Correct?
Section titled “Is Your Inheritance Hierarchy Correct?”One way to check whether your classes have been organised correctly is to apply the “IS-A” and “IS-PART-OF” relationship tests. It is easy to confuse objects that belong to a class with classes that are derived from others when first learning object-oriented programming.
Inheritance: What an Object IS
Section titled “Inheritance: What an Object IS”The IS-A relationship describes inheritance. To verify the relationship between Car and Vehicle, as shown in Figure 10, we can apply the IS-A test: a Car IS-A Vehicle, confirming the inheritance relationship. For example, we can say “A Car IS-A Vehicle” and “A SaloonCar IS-A Car”, confirming that these inheritance relationships are correct.
Composition: What an Object HAS
Section titled “Composition: What an Object HAS”The IS-PART-OF (or HAS-A) relationship refers to composition (or aggregation) within a class. In Figure 10, we can say “An Engine IS-PART-OF a Vehicle” or “A Vehicle HAS-AN Engine, Colour, and Wheels”. This holds true even though Engine is also a class, which itself could have multiple variations, such as PetrolEngine, ElectricEngine, DieselEngine, and so on.

Vehicle class.
By using inheritance, the programmer can:
- Inherit behaviour and add specialised behaviour — for example, a
CarIS-AVehiclewith additional components such as fourWheelobjects,Seats, etc. - Inherit behaviour and replace it — for example, the
SaloonCarclass inherits from Car but provides a new implementation for the boot. - Reduce the amount of code that needs to be written and maintained — since only the differences between classes need to be specified. For instance, a
SaloonCaris largely identical to aCar, with only the additional or modified features requiring explicit definition.
🧩Knowledge Check
Section titled “🧩Knowledge Check”Build the Vehicle Hierarchy
Build the University Hierarchy
Polymorphism
Section titled “Polymorphism”When a class inherits from another class, it inherits both the states and methods of that class. For example, when the Car class inherits from the Vehicle class, it acquires the methods of Vehicle, such as startEngine(), changeGear(), setLightsOn(), and so on. It also inherits the states of Vehicle, such as EngineOn, LightsOn, numberWheels, etc.
Polymorphism means “multiple forms”. In object-oriented programming, this refers to the ability to use the same method name in different ways — either across different classes or within the same class but with different parameters. There are two primary forms of polymorphism:
- Overriding: where a subclass provides its own implementation of a method inherited from the base class.
- Overloading: where multiple methods in the same class share the same name but differ in their parameter lists.
Overriding
Section titled “Overriding”As discussed, a derived class inherits methods from its base class. However, it may sometimes be necessary to redefine an inherited method to provide behaviour specific to the derived class, thereby modifying its implementation. This is known as overriding — where the same method name is called on different objects, but each object responds according to its own implementation of the method.
Overriding allows different types of objects that share common behaviour to be used interchangeably in code that only depends on that shared behaviour.

draw() method.
Consider the previous example of the Vehicle class diagram in Figure 11. In this case, Car inherits from Vehicle, and from Car there are further derived classes: SaloonCar and EstateCar. Note that while we introduce the draw() method here at the Car level for simplicity, in a more complete model it would often be defined in the Vehicle base class (as we will see in the section on Abstract Classes). If a draw() method is added to the Car class to draw a generic vehicle, it may not be sufficient for more specific vehicles such as the EstateCar.
Overriding allows us to write a specialised draw() method for the EstateCar class, while reusing the existing draw() method from the Car class for the SaloonCar, as it remains adequate. To override, we simply write a new draw() method in the EstateCar class using the exact same method name.
Overriding provides two key advantages:
- A simpler Application Programming Interface (API), as we can call methods by the same name across different classes, even when their internal behaviour differs slightly.
- A higher level of abstraction, as the implementation details remain hidden from the user.
Overloading
Section titled “Overloading”Overloading is the second form of polymorphism. In this case, the same method name is used, but the number or types of parameters differ, allowing the compiler to determine which version of the method to call. For example:
add(int x, int y)add(String x, String y)These are two distinct methods that share the same name and number of parameters but operate on different data types. If we pass two int values, we expect numeric addition (e.g. 6 + 7 = 13). However, if we pass two String objects, we expect string concatenation (e.g. "6" + "7" = "67").
The number of arguments can also be used to differentiate methods. For example:
channel()channel(int x)In this case, the first method may simply display the current channel number, while the second allows the channel to be set to the specified value.
Abstract Classes
Section titled “Abstract Classes”An abstract class is a class that is incomplete — it defines a set of operations but lacks the actual implementation for some or all of those operations. Abstract classes have the following characteristics:
- They cannot be instantiated directly.
- They can only be used through inheritance.
For example, in the earlier Vehicle class, the draw() method may be declared as abstract, since it is not meaningful to draw a generic vehicle. This approach forces all derived classes to provide their own implementation of the draw() method if they are to be instantiated.
As previously discussed, a class can be thought of as a set of plans used to create objects. Extending this analogy, an abstract class is like a set of plans with missing details — for instance, a car design without an engine. Without completing the missing parts, it would not be possible to create fully functional objects.

draw() method in the Vehicle class.
Figure 12 illustrates this example. The draw() method has been implemented in all the classes and provides some functionality. In the Vehicle class, draw() is marked as abstract, which means the class is incomplete and cannot be instantiated — in other words, we cannot create objects of the Vehicle class.
In Figure 12, the SaloonCar class does not define its own draw() method, but it inherits the implementation from its parent Car class. Therefore, it is possible to create objects of SaloonCar.
If desired, we could also mark the draw() method as abstract in a derived class. For example, if draw() were tagged as abstract in the Car class, it would not be possible to instantiate Car directly. Instead, responsibility for implementing the draw() method would pass down to its child classes, as shown in Figure 13.

draw() method in the Vehicle and Car classes.
🧩Knowledge Check
Section titled “🧩Knowledge Check”Build the Shape Hierarchy
Build the Sensor Hierarchy
Code Case Conventions (Camel, Snake & Kebabs!)
Section titled “Code Case Conventions (Camel, Snake & Kebabs!)”In programming, clear and consistent naming conventions are crucial for readability and maintainability. Character case formats play a significant role in achieving this, helping to differentiate between various code elements.
One of the most common formats is Camel Case, which combines words by capitalising the first letter of each word except the very first**. For example, myVariableName or calculateTotalAmount. A closely related style is Pascal Case (sometimes called Upper Camel Case), where the first letter of every word, including the first, is capitalised, such as ClassName or ProcessData. In the notes for this section, we adhere to the convention where a Class name always begins with a capital letter (e.g., MyClass), while a state variable or method will begin with a lowercase letter (e.g., currentTemperature, calculateValue()), aligning with the camelCase convention.
Another widely used format is Snake Case, where words are separated by underscores, and all letters are typically lowercase (e.g., my_variable_name, calculate_total_amount). This is common in Python and some C/C++ codebases. For constants or immutable values, a variant called** Screaming Snake Case or Uppercase Snake Case is used, where all letters are uppercase and words are separated by underscores (e.g., MAX_ARRAY_SIZE, PI_VALUE).
Less common in general-purpose programming but prevalent in web development (especially CSS and URLs) is Kebab Case, which uses hyphens to separate lowercase words (e.g., my-component-name, calculate-price). While other less common styles exist (like flat case myvariable, or dot.case my.variable), these five form the core set you’ll encounter, each serving to improve clarity and structure within code. Consistency in applying these conventions across a project is important for team collaboration and long-term communication and understanding. See Figure 14.

🧩Knowledge Check
Section titled “🧩Knowledge Check”Which of the following code examples correctly follow the naming conventions described in this chapter?
Match the format name to its correct visual representation:
Final Self-Evaluation
Section titled “Final Self-Evaluation”To conclude this chapter, use the tool below to build a complete hierarchy that incorporates abstract classes and inheritance.
Build the Vehicle Hierarchy (Abstract)
© 2026 Derek Molloy, Dublin City University. All rights reserved.