Learning Objectives
After completing this session, you will be able to: Explain basics of OOPS
Explain Classes and Objects
Define Abstraction, Encapsulation, Inheritance, and Polymorphism
Fundamentals of object-oriented programming
The fundamental principle of object-oriented programming is that a program is composed of a collection of individual units, or objects that can function like sub-programs. To make the overall computation happen, each object is capable of receiving messages, processing data, and sending messages to other objects. In short, the objects can interact through their own functions (or methods) and their own data.
The key to understanding object-oriented design is understanding what classes are and what you can do with them. Classes are templates that you use to create actual objects. The instructions contained in a class are used to create one or more objects, which can be called instances of classes. When you create an object from a class, you instantiate the object, which means you create an instance of the class.
In object-oriented programming, you can think of an object as you would any real-world object, for example, a rectangle. The actual rectangle would be an instance of the class Rectangle.
A very rudimentary declaration of a class is as follows: Class Rectangle {
//class instructions
}
The instructions in a class are made of two basic components: variables that hold data, and methods that manipulate the data.
Variables:
Classes store information that describes objects in instance variables. When objects are created from a class, they contain new instances of the class' variables. These instance variables can have values that are different from one object to the next. Values of instance variables are called data. When an instance variable's data is changed, it affects only the individual object.
Methods:
Methods are functions that must be associated with individual classes. In C and C++ and other procedural languages, functions can be placed anywhere in the code. In C#, they must be stored within classes. Instances of methods are created when instances of classes are created. Unlike variables, methods are not duplicated in objects-their code is stored only in the class.
When an object's method is invoked from its class, it uses the data of variables in the object.
Every method returns a value if it is not declared as void. To declare a method, you use the following statement:
returntype methodname (parameter list) {
//method code }
Characteristics of an object-oriented language
Object-oriented programming emphasizes the following concepts:
Objects: Packaging data and functionality together into units within a running program; objects are the basis of modularity and structure in an object-oriented program.
Abstraction: The ability for a program to ignore some aspects of the information that it is
manipulating, i.e. the ability to focus on the essential. Each object in the system serves as a model of an abstract "actor" that can perform work, report on and change its state, and "communicate" with other objects in the system, without revealing how these features are implemented.
Processes, functions or methods may also be so abstracted, and when they are, a variety of techniques are required to extend an abstraction:
Encapsulation: Also called information hiding: Ensures that users of an object cannot change the internal state of the object in unexpected ways; only the object's own internal methods are allowed to access its state. Each class exposes an interface that specifies how other classes may interact with it. This prevents users from breaking the invariants of the class, which is useful because it allows the implementation of a class of objects to be changed for aspects not exposed in the interface without impact to user code. The definitions of encapsulation focus on the grouping and packaging of related information (cohesion) rather than security issues. OOP languages do not normally offer formal security restrictions to the internal object state. Using a method of access is a matter of convention for the interface design.
Polymorphism: Different things or objects can have the same interface or answer the same message (based on message name) and respond appropriately depending on the thing's nature or type. This potentially allows multiple things to be interchangeable with each other. For example, if a bird receives the message "move fast", it will flap its wings and fly. If a lion receives the same message, it will run with its legs. Both answer the same request, but in ways appropriate to each creature.
Inheritance: Organizes and facilitates polymorphism and encapsulation by permitting objects to be defined and created that are specialized types of already-existing objects - these can share (and extend) their behavior without having to reimplement that behavior. This is typically done by grouping objects into classes, and defining classes as extensions of existing classes, thus and grouping classes into trees or lattices reflecting behavioral commonality.
Inheritance, Overriding and Overloading
If you want an object that is very similar to one we already have, but with a few extra
characteristics. You just inherit a new class based on the class of the similar object. Inheritance is the process of creating a new class with the characteristics of an existing class, along with additional characteristics unique to the new class. Inheritance provides a powerful and natural mechanism for organizing and structuring programs.
Members and methods that are stored in classes in the class hierarchy are inherited by
subclasses, so you do not need to re-create them. Objects created from a subclass will contain not only the instances of the variables and methods of the child class, but also its parent class'
members and methods, as well as those of the parent of its parent class, and so on. When a members or method is referenced in an object, it is retrieved in a specific order: compiler first searches for it in the current class, then, if it is not found, it searches the parent class, and so on.
Class inheritance is designed to allow as much flexibility as possible. You can create inheritance trees as deep as necessary to carry out your design. An inheritance tree, or class hierarchy, looks much like a family tree; it shows the relationships between classes. Unlike a family tree, the classes in an inheritance tree get more specific as you move down the tree.
You create a derived class by adding a colon after the name of the derived class, followed by the name of the base class:
Calling Base Class Constructors
The Honda class constructor invokes the constructor of its parent by placing a colon (:) after the parameter list and then invoking the base class with the keyword base.
If the base class has an accessible default constructor, the derived constructor is not required to invoke the base constructor, as the default constructor is called implicitly. If the base class does not have a default constructor, every derived constructor must explicitly invoke one of the base class constructors using the base keyword.
public void Honda() : base {
this.Model = "Honda"; }
Calling Base Class Methods
If a class needs to call a method in the base class then this is achieved using the base keyword followed by the method required in the usual manner using dot notation.
base.StartCar();
Unlike C++, multiple inheritances are not allowed in C# and a similar effect can be achieved using interfaces, which is discussed shortly.
In some cases, a class may want to 'overwrite' a base method. C# supports two different ways of method overwriting - 'hiding' or 'overriding'. Note that the term 'overwrite' is a term we have devised to cover both hiding and overriding.
Method overwriting makes use of the following three method-head keywords: new, virtual,
override. The main difference between hiding and overriding relates to the choice of which method to call where the declared class of a variable is different to the run-time class of the object it references. This point is explained further below.
Method Overriding
Suppose that you define a Square class which inherits from a Rectangle class (a square being a special case of a rectangle). Each of these classes also specifies a 'getArea' instance method, returning the area of the given instance.
For the Square class to 'override' the Rectangle class' getArea method, the Rectangle class' method must have first declared that it is happy to be overridden. One way in which it can do this is with the 'virtual' keyword. So, for instance, the Rectangle class' getArea method might be specified like this:
public virtual double getArea() {
return length * width; }
To override this method the Square class would then specify the overriding method with the 'override' keyword. For example:
public virtual double getArea() {
return length * length; }
Note that for one method to override another, the overridden method must not be static, and it must be declared as either 'virtual', 'abstract' or 'override'. Furthermore, the access modifiers for each method must be the same. The major implication of the specifications above is that if we construct a new Square instance and then call its 'getArea' method, the method actually called will be the Square instance's getArea method. So, for instance, if you run the following code:
Square sq = new Square(5); double area = sq.getArea();
Then the getArea method called on the second line will be the method defined in the Square class. There is, however, a more subtle point. To show this, suppose that you declare two variables in the following way:
Square sq = new Square(4); Rectangle r = sq;
Here variable r refers to sq as a Rectangle instance (possible because the Square class derives from the Rectangle class). You can now raise the question: if you run the following code
double area = r.getArea();
Then which getArea method is actually called - the Square class method or the Rectangle class method? The answer in this case is that the Square class method would still be called. Because the Square class' getArea method 'overrides' the corresponding method in the Rectangle class, calls to this method on a Square instance always 'slide through' to the overriding method.
Method Hiding
Where one method 'hides' another, the hidden method does not need to be declared with any special keyword. Instead, the hiding method just declares itself as 'new'. So, where the Square class hides the Rectangle class' getArea method, the two methods might just be written thus: public double getArea() // in Rectangle
{
return length * width; }
public new double getArea() // in Square {
return length * length; }
Note that a method can 'hide' another one without the access modifiers of these methods being the same. So, for instance, the Square's getArea method could be declared as private,
Overloaded Methods
You use overloaded methods in your code when you need to call a method with different sets of parameter lists. Methods that allow flexibility in the parameters they use can be called from different parts of your program with different variables. To allow a different type of parameter information to be passed to your method, repeat the method in your code with the alternate parameter list included, as follows:
returnvalue methodname (parameter list 1) returnvalue methodname (parameter list 2)
It is possible to extend when the method is called and parameters are passed to it, compiler determines which version of the method has a parameter list that most closely matches the parameters passed and executes it.
Polymorphism
Through inheritance, a class can be used as more than one type; it can be used as its own type, any base types, or any interface type if it implements interfaces. This is called polymorphism.
Polymorphism is important not only to the derived classes, but to the base classes as well. Anyone using the base class could, in fact, be using an object of the derived class that has been cast to the base class type.
Polymorphism means that you can have multiple classes that can be used interchangeably, even though each class implements the same properties or methods in different ways. Polymorphism is essential to object-oriented programming because it allows you to use items with the same names, no matter what type of object is in use at the moment.
When a derived class inherits from a base class, it gains all the methods, fields, properties and events of the base class. To change the data and behavior of a base class, you have two choices: you can replace the base member with a new derived member, or you can override a virtual base member.
Replacing a member of a base class with a new derived member requires the new keyword. The new keyword is placed before the return type of a class member that is being replaced.
Example:
public class BaseClass {
public void DoWork() { } public int WorkField; public int WorkProperty {
get { return 0; } }
public class DerivedClass : BaseClass {
public new void DoWork() { } public new int WorkField; public new int WorkProperty {
get { return 0; } }
}
When the new keyword is used, the new class members are called instead of the base class members that have been replaced. Those base class members are called hidden members. Hidden class members can still be called if an instance of the derived class is cast to an instance of the base class. For example:
DerivedClass B = new DerivedClass(); B.DoWork(); // Calls the new method.
BaseClass A = (BaseClass)B;
A.DoWork(); // Calls the old method.
In order for an instance of a derived class to completely take over a class member from a base class, the base class has to declare that member as virtual. This is accomplished by adding the virtual keyword before the return type of the member. A derived class then has the option of using the override keyword, instead of new, to replace the base class implementation with its own.
Example:
public class BaseClass {
public virtual void DoWork() { } public virtual int WorkProperty {
get { return 0; } }
}
public class DerivedClass : BaseClass {
public override void DoWork() { } public override int WorkProperty {
get { return 0; } }
Fields cannot be virtual, only methods, properties, events and indexers can be virtual. When a derived class overrides a virtual member, that member is called even when an instance of that class is being accessed as an instance of the base class.
Example:
DerivedClass B = new DerivedClass(); B.DoWork(); // Calls the new method.
BaseClass A = (BaseClass)B;
A.DoWork(); // Also calls the new method.
Summary
Abstraction is used to manage complexity. Encapsulation promotes “information hiding”. Inheritance aids in the reuse of code.
Polymorphism means ability to take more than one form.
Test your Understanding
1. Why do you need to go for OOPS?
2. Differenciate between Object Oriented and Procedural Oriented programming. 3. What are classes and objects?
4. What is Inheritance? 5. What is Polymorphism?