A-level Computing/AQA/Paper 1/Fundamentals of programming/Features of Object-Oriented Programming

OOP imposes additional structure on programs. We have introduced two new structural features: Objects, and Classes. We have also seen how ordinary Variables and Procedures are given extra rules, and renamed as Attributes and Methods. OOP languages often have ordinary Variables and Procedures too, but mostly we work with the Object-specific versions; this is what we mean by "Object oriented" - we are actively using Objects in our program design and implementation.

This additional structure allows us to do new things in programming that weren't possible with ordinary Procedure-oriented programming. In later sections, we will see how these can help building larger and more complicated programs, while reducing the number of bugs and making them easier to work with.

Instantiation and Constructors
We have two new structuring concepts: Classes, and Objects. How do we create them?

The Class is a new data-type, so we specify it in source code. Typically, we create a new source file and name it the same as we want to name our Class. So, a "Car" class might be described by a source file called "Car.src" (in Java: "Car.java", in Python: "Car.py", etc).

But how do we create new Objects - how do we use our Class as a template to create many Objects for us?

This process is called Instantiation: when the program is running, we invoke a special Method (i.e. Procedure) within the Class that Instantiaties a new Object. (The object created is referred to as an Instance of the class) These special Methods are the same as ordinary Methods, but in some languages they have different syntax, or additional tags, to make clear they are intended for creating new Objects.

Because these Methods have a special purpose, and to make it easier to talk about them without getting confused with the general Methods on the Object, we have a special name for Methods that can Instantiate new Objects. These Methods are called Constructors.

To recap:


 * A Constructor is a kind of Method. It has the extra feature that it creates (instantiates) new Objects.
 * A Method is a kind of Procedure. It has the extra rule that it must be part of a Class and/or Object.
 * A Procedure in OOP is the same as a Procedure in non-OOP languages.

The code above creates an object called polo and escort, both of class type car (which we declared earlier). We can now use all the public attributes and methods: This would output the following:

pumping gas!

pumping gas!

pumping gas!

polo: 89

escort: 29

Write your own instantiation for a beetle car:

What would the following output:

pumping gas!

pumping gas!

pumping gas!

ka: 20

montego: 37

Polymorphism
In Procedure-oriented programming, data available to one method is generally available to all methods. This can be manually restricted, e.g. using private/protected/etc, see Encapsulation [link needed here], but this is optional. Usually the only limit is that the data provided to each Procedure must match specific ../Data types. When defining the Procedure, we choose which datatypes it will accept (i.e. we restrict the Parameters).

EXAMPLE: ---datatypes: 2 procedures eg int int and string int

When someone tries to use the Procedure, the computer looks at the data provided, and compares the datatypes to ....( so long as the types of data they provide exactly match the types we choose, the Procedure will execute.)

In Object-oriented programming, all data is encapsulated by default [for multiple reasons - link needed]. Unlike Procedure-oriented programming, where any Procedure can access any data anywhere in the program, Methods can only directly access data in their own object. To access the data within a different object, we must pass the whole object to any Methods (or Procedures) that need to act on that data.

This creates a problem: the datatype of the parameter will now be the type of the object's class, and each class is a unique datatype. For a simple case, this works fine, but for larger problems it prevents us re-using Methods. This would be disastrous for OOP: we would need to endlessly copy/paste Methods from one Class to another, tweaking the parameter-types, instead of re-using the code. This would be a step backwards in ease of programming and reduction of bugs.

For example, if we have a Pet class with a Year_of_Birth variable, and an Owner class that also has a Year_of_Birth variable, and we have a method that calculates current Age from a Year_of_Birth ... it will either work on Pet classes, or on Owner classes, but it cannot work on both.

To solve this, OOP languages have an essential feature called Polymorphism. There are many kinds of Polymorphism, but most of the time we only use two of them. The shared concept is that one thing can pretend to be multiple things.

Ad-hoc Polymorphism
The simplest form of Polymorphism is Ad hoc polymorphism when the programmer writes multiple different versions of the Procedure: e.g. one that accepts Objects of type A, and one that accepts Objects of type B. Both versions have the same name, and the OOP language knows to treat them as if they are the same, but to intelligently use one or the other depending on how the Procedure is invoked at runtime.

Subtype polymorphism
The more powerful form, used heavily in OOP, is Subtyping. With subtype polymorphism, the programmer links different datatypes to each other, promising the computer that - in some way - those datatypes can be used interchangeably. The mechanism for this is Inheritance (see below).

Consider our car example again. When we created the  object we inherited from   and added the   attribute and methods. But what happens when we try and refuel, let's take a look at the code: Well this just won't do. We are creating an electric car and we don't want to say that we are pumping gas; what would our sandal-socked yoghurt eating friends say! So for the  object we want to inherit everything from , but we want to morph(change) the   method. To do that we are going to use something called override:

In polymorphism what is the keyword we use to redefine a subroutine:

overrides

Write a definition of a limo class that uses polymorphism that makes sure that the maxSpeed never goes beyond 100:

Write a definition of musclecar that inherits car, but uses 30 units of fuel per drive and displays "vroom vroom!" every time it drives. It should also store details on leatherSeating, allowing you to interface with this.

Describe polymorphism

Polymorphism allows you to inherit attributes from a parent class, but redefine some of the methods or attributes

Inheritance
In practice, the simple version of Polymorphism above would not save much programmer time if we end up writing different versions of a similar method for each type.

To fix this problem, OOP languages use Inheritance (also called Subclassing, if types are implemented as classes).

When one Class Inherits from another Class, it adopts the type of the other Class, and adopts all the Methods and Attributes. The new Class can be treated as if it is the old Class - Procedures don't need to know whether they are seeing a new Class or an old one.

The original Class is usually called a superclass and the new (inheriting) Class is called a subclass.

Crucially, the subclass is allowed to add additional Methods and Attributes on top of the ones it inherited. Because these new features extend the behaviour of the superclass, we usually say that a subclass "extends" the superclass. In some OOP languages, the syntax for making a subclass is to use a keyword "extends", along with the superclass you wish to inherit from.

For example, the Shape class may define variables and methods common to any shape (eg number of vertices, colour, position) which are inherited by subclasses, which then access the same code, where appropriate, while providing subclass specific methods for area - see Overriding below.

For example, theShape.area would invoke a method from the class of which theShape is an instance, which would be different methods when theShape was an instance of a polygon or an ellipse.

Subtype refers to a hierarchy of types, where both ellipse and polygon are subtypes of a supertype Shape. The method used may be selected at run time (in some languages), so that the code which invokes theShape.area need not know what subtype theShape belongs to, so long as it provides a method area.

However, this comes at a price - changes in the superclass may produce unwanted side effects in some subclasses.

Declare a new class called limo that has attributes numSeats and colourSeats; and the ability to interface with them

What are the benefits of using inheritance? Creating new classes from parent classes is very quick and easy. It allows for a modular approach to creating classes, where you might never use the base class at all.

Building on the car example above, what would happen if we wanted to declare an electric car? Well we'd probably want to store some information on the number of batteries that it has: This seems like a very long and tedious task rewriting all the same code again. You're right! It would be far better if we only had to declare all the new stuff we wanted to add. OOP allows for inheritance, where a new class can inherit the attributes and methods of a parent class: This means that everything that car declared is now accessible from electricCar, as well as the new numBatteries attribute and methods. Let's instantiate this example and see what's possible

Overriding
Inheritance (aka Subclassing) and Polymorphism largely solve the issues caused by Methods and Attributes being more restricted than plain Procedures and Variables. But we quickly discover that not only do we want to extend a superclass (i.e. add to its existing Methods/Attributes), but we want to modify its existing behaviour.

This is so useful that most OOP languages support it as core feature, and this is called Overriding.

When a subclass extends a superclass, it can optionally replace any of the superclass's Methods with new, customized versions. This act of replacing is Overriding, and the old version is described as overridden.. The replacement method in the subclass may (but need not) invoke the overridden method of the superclass, as well as carrying out additional operations required by the subclass.

Overloading
Most OO languages allow redefinition of the standard arithmetic operators (+,-,*,/,...) so they can be applied to members of a class, or to a class and a standard variable type ( real number, integer,..). As with polymorphism, the appropriate method (which must be part of the class definition) may be selected at run time.

For example, a class Complex which represents complex numbers, could implement the standard arithmentical operations for its instances.

Technically, Overloading is a kind of ad-hoc polymorphism, but it is so widely used that it has its own name.

Examples

 * ../OOP Examples of key features