Object-oriented programming (OOP) is a programming language model organized around "objects" rather than "actions" and data rather than logic. Historically, a program has been viewed as a logical procedure that takes input data, processes it, and produces output data. OOPS programming paradigm advocates solving real world problems by imitating real world entities (objects) and their interaction.
The first step in OOP is to identify all the objects to be manipulated and how they relate to each other, an exercise often known as data modeling. Once identified an object, generalize it as a class of objects and define the kind of data it contains and any logic sequences that can manipulate it. Each distinct logic sequence is known as a method. A real instance of a class is called an "object" or, an "instance of a class." Users communicate with objects - and they communicate with each other - with well-defined interfaces called messages.
The concepts and rules used in object-oriented programming provide these important benefits:
- The concept of a data class makes it possible to define subclasses of data objects that share some or all of the main class characteristics. Called inheritance, this property of OOP forces a more thorough data analysis, reduces development time, and ensures more accurate coding.
- Since a class defines only the data it needs to be concerned with, when an instance of that class (an object) is run, the code will not be able to accidentally access other program data. This characteristic of data hiding provides greater system security and avoids unintended data corruption.
- The definition of a class is reusable not only by the program for which it is initially created but also by other object-oriented programs (and, for this reason, can be more easily distributed for use in networks).
- The concept of data classes allows a programmer to create any new data type that is not already defined in the language itself.
In object-oriented programming, a class is a construct that is used to create instances of it – referred to as class instances, class objects, instance objects or simply objects. A class defines constituent members which enable its instances to have state and behavior. Data field members (member variables or instance variables) enable a class instance to maintain state. Other kinds of members, especially methods, enable the behavior of a class instances. Classes define the type of their instances.
Classes are composed of structural and behavioral constituents.
Structure
A class contains data field descriptions (or properties, fields, data members, attributes), usually field types and names, that will be associated with state variables at program run time; these state variables either belong to the class or specific instances of the class. In most languages, the structure defined by the class determines the layout of the memory used by its instances
Behavior
The behavior of class or its instances is defined in methods. A method is a subroutine with the ability to access data stored in an instance object or class and is thereby able to control its state. The various kinds of methods and language support for them differ. Kinds of methods include those that are created and called by programmer code and special methods that are created and called by compiler-generated code, such as constructors, destructors, and conversion operators.
"Objects" are the foundation of object-oriented programming, and are fundamental data types in object-oriented programming languages. In object-oriented programming an object is usually taken to mean a brief compilation of attributes (object elements / members) and behaviors (methods or subroutines) encapsulating an entity. In short, object can be described as instance of a class.
In this way, while primitive or simple data types are still just single pieces of information, object-oriented objects are complex types that have multiple pieces of information & specific properties (or attributes) and methods to manipulate the information. Instead of merely being assigned a value, (like int i=10), objects have to be "constructed".
There are certain specialized objects which can be created by the kind of Design Pattern which is used for creating them and usually those objects are named after their design patterns themselves. Some terms for specialized kinds of objects include:
- Function object: an object with a single method (in C++, this method would be the function operator, "operator()") that acts much like a function (like a C/C++ pointer to a function).
- Immutable object: an object set up with a fixed state at creation time and which does not vary afterward.
- First-class object: an object that can be used without restriction.
- Container: an object that can contain other objects.
- Factory object: an object whose purpose is to create other objects.
- Prototype: a specialized metaobject from which other objects can be created by copying
- God object: an object that knows too much or does too much. The God object is an example of an anti-pattern.
- Singleton object: An object that is the only instance of its class during the lifetime of the program.
Abstraction - a concept or idea not associated with any specific instance.
Abstraction is the process by which data and programs are defined with a representation similar in form to its meaning (semantics), while hiding away the implementation details. Abstraction tries to reduce and factor out details so that the programmer can focus on a few concepts at a time.
Abstraction captures only those details about an object that are relevant to the current perspective.
Abstraction can apply to control or to data: Control abstraction is the abstraction of actions while data abstraction is that of data structures.
- Control abstraction involves the use of subprograms and related concepts control flows
- Data abstraction allows handling data bits in meaningful ways. For example, it is the basic motivation behind data type.
Advantages
Abstraction is simplifying complex reality by modeling classes appropriate to the problem, and working at the most appropriate level of inheritance for a given aspect of the problem.
The abstraction principle (or the principle of abstraction) is a basic dictum that aims to reduce duplication of information in a program. The abstraction principle can be generalized as the "don't repeat yourself" principle, which recommends avoiding the duplication of information in general, and also avoiding the duplication of human effort involved in the software development process.
“Each significant piece of functionality in a program should be implemented in just one place in the source code. Where similar functions are carried out by distinct pieces of code, it is generally beneficial to combine them into one by abstracting out the varying parts.”
For example: a = (1 + 2) * 5;
To a human, this seems a fairly simple and obvious calculation ("one plus two is three, times five is fifteen"). However, the values need to be converted to binary representation and the calculations decomposed into assembly instructions. Finally, assigning the resulting value of "15" to the variable labeled "a", so that "a" can be used later.
Here, the implementation is hidden (conversion, assembly instructions, assigning results), though it gives the user a complete understanding of the behavior. Also the above expression is not associated with any specific instance of numbers (integers). This works seamlessly for any numbers (integer, float, double etc.).
Encapsulation means that the internal representation of an object is generally hidden from view outside of the object's definition. Typically, only the object's own methods can directly inspect or manipulate its fields.
Encapsulation is used to refer to one of two related but distinct notions, and sometimes to the combination of both:
- A mechanism for restricting access to some of the object's components.
- A construct that facilitates the bundling of data with the methods (or other functions) operating on that data, i.e., providing the boundary of class members.
Advantage
Hiding the internals of the object protects its integrity by preventing users from setting the internal data of the component into an invalid or inconsistent state. A benefit of encapsulation is that it can reduce system complexity, and thus increases robustness, by allowing the developer to limit the interdependencies between software components.
Polymorphism - many forms (‘poly’ means many & 'morphs' means forms).
In OOPS polymorphism refers to the ability of a method to provide different behaviors. It is a feature that allows one interface to be used for general class of actions. The specific action is determined by the exact nature of the situation. In general polymorphism means "one interface, multiple methods", This means that it is possible to design a generic interface to a group of related activities. This helps reduce complexity by allowing the same interface to be used to specify a general class of action.
In other words, it allows having multiple functionalities for a single function name.
Compile time Polymorphism / Static Polymorphism / Early Binding / Overloading
Ad-hoc polymorphism to refer to polymorphic functions which can be applied to arguments of different types, but which behave differently depending on the type of the argument to which they are applied (also known as function overloading or operator overloading). The term "ad hoc" in this context refers simply to the fact that this type of polymorphism is not a fundamental feature of the type system.
class Adhoc_Polymorph
{
int Add(int a, int b)
{
return a + b;
}
string Add(string a, string b)
{
return a + b;
}
}
In the example above, the Add functions seems to work generically over various types when looking at the invocations, but are considered to be two entirely distinct functions by the compiler for all intents and purposes.
Ad hoc polymorphism only considers the ‘number of arguments’ or ‘type of arguments’ to be different for a given function name. It does not consider the return type of the function.
Generics / Advanced Template Library (C++)
Parametric polymorphism allows a function or a data type to be written generically, so that it can handle values identically without depending on their type. Parametric polymorphism is a way to make a language more expressive, while still maintaining full static type-safety.
Background
Before .NET 2.0, generalization was accomplished by casting types to and from the universal base type System.Object. This limitation can be demonstrated with the help of the ArrayList collection class from the .NET Framework base class library. ArrayList is a highly convenient collection class that can be used without any modifications to store any reference or value type.
class NonGeneric
{
void CreateList()
{
ArrayList myList = new ArrayList();
myList.Add(7);
myList.Add("007");
int i = (int) myList[0];
}
}
Any reference or value type that is added to an ArrayList is implicitly typecast to System.Object. If the items are value types, they must be boxed when added to the list, and unboxed when they are retrieved. A programmer must typecast the object to its actual type while retrieving the data from list. The casting, boxing and unboxing operations degrade performance.
Generics would eliminate the need for all items to be type cast to System.Object and would also enable the compiler to do some type checking. In the generic List<T> collection, in System.Collections.Generic namespace; the same operation of adding items to the collection is as follows:
class Generic
{
void CreateList()
{
List<int> myList = new List<int>();
myList.Add(1);
myList.Add(4);
myList.Add(7);
}
}
Generic classes encapsulate operations that are not specific to any particular data type. A typical example of Generic class is given below:
public class Generic<T>
{
private T MemberVariable;
public T GetMember()
{
return MemberVariable;
}
public void SetMember(T value)
{
MemberVariable = value;
}
}
Run time Polymorphism / Dynamic Polymorphism / Late Binding / Overriding
The idea of subtypes is to restrict the range of types that can be used in a particular case of parametric polymorphism. Subtype polymorphism (sometimes referred to as dynamic polymorphism) allows a function to be written to take an object of a certain type T, but also work correctly if passed an object that belongs to a type S that is a subtype of T. This type relation is sometimes written S <: T (S is subtype of T), conversely, T:>S (T is supertype of S).
Object-oriented programming languages offer subtype polymorphism using subclass (also known as inheritance). In typical implementations, each class contains what is called a virtual table ("vtable")—a table of functions that implement the polymorphic part of the class interface—and each object contains a pointer to the "vtable" of its class, which is then consulted whenever a polymorphic method is called.
abstract class Animal
{
string talk();
}
public class Cat : Animal
{
string talk() { return "Meow!"; }
}
public class Dog : Animal
{
string talk() { return "Woof!"; }
}
The similar implementation is carried out when one of the methods in a class is declared as virtual.
public class Animal
{
public virtual string talk() { return ""; }
}
public class Cat : Animal
{
public override string talk() { return "Meow!"; }
}
public class Dog : Animal
{
public override string talk() { return "Woof!"; }
}
Name mangling (also called name decoration) is a technique used to solve various problems caused by the need to resolve unique names for programming entities. It provides a way of encoding additional information in the name of a function, structure, class or another data type in order to pass more semantic information from the compilers to linkers.
e.g. consider the three functions below:
int f (void) { return 1; }<?xml:namespace prefix = o />
int f (int x) { return x; }<?xml:namespace prefix = o />
void g (void) { int i = f(), j = f(0); }
The compiler therefore will encode the type information in the symbol name, the result being something resembling:
int __f_v (void) { return 1; }<?xml:namespace prefix = o />
int __f_i (int) { return 0; }<?xml:namespace prefix = o />
void __g_v (void) { int i = __f_v(), j = __f_i(0); }
Inheritance is a way to reuse code of existing objects, or to establish a subtype from an existing object. In classical inheritance where objects are defined by classes, classes can inherit attributes and behavior (i.e., previously coded algorithms associated with a class) from pre-existing classes called base classes or superclasses or parent classes or ancestor classes. The new classes are known as derived classes or subclasses or child classes. The relationships of classes through inheritance give rise to a hierarchy.
Consider a class Person that contains a person's name, address, phone number, age, and gender. We can define a subclass of Person called Student that contains the person's grade point average and classes taken, and another subclass of Person called Employee that contains the person's job-title, employer, and salary.
-
Singleness: Using single inheritance, a subclass can inherit from only one superclass. Person can be either a Student or an Employee, but not both. Using multiple inheritance partially solves this problem.
-
Static: It does not allow a Student object to become an Employee object while retaining the state of its Person superclass. Although similar behavior can be achieved with the decorator pattern.
Symbol

Multilevel inheritance is a feature of OOPS; in which a class can inherit behaviors and features from one superclass; and another class inherits from the subclass.

Multiple inheritance is a feature of OOPS; in which a class can inherit behaviors and features from more than one superclass. Multiple inheritance has been criticized for its unnecessary complexity and being difficult to implement efficiently. .NET does not support multiple inheritance directly; though this can be achieved using Interfaces.
Multiple inheritance is not supported directly in .NET as it gives rise to classic Diamond Problem. The diamond problem is an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C. If D calls a method defined in A (and does not override the method), and B and C have overridden that method differently, then from which class does it inherit: B, or C?

Button class inherits two different implementations of equals() while it has no own implementation of the operation. When button.equals() is called, it is unknown which implementation - from Rectangle or from Clickable - will be used.
Solution: C++ by default follows each inheritance path separately, so a Button object would actually contain two separate Object objects, and uses of Object's members have to be properly qualified. If the inheritance from Object to Rectangle and the inheritance from Object to Clickable are both marked "virtual" (for example, "class Rectangle : virtual public Object"), C++ takes special care to only create one Object object, and uses of Object's members work correctly.
If virtual inheritance and non-virtual inheritance are mixed, there is a single virtual Object and a non-virtual Object for each non-virtual inheritance path to Object. Please note that non-virtual derivation of Object in this case will be useless as direct access to any part of class Object from class Button will practically always end up with compile error.
Below are the basic levels of access that are supported by almost all object oriented languages:
Private: Private data members and member functions can’t be accessed outside the class. However there is an exception, private members can be accessed by using friend classes.
Public: Public data members and member functions are accessible outside the class.
Protected: Protected data members and member functions are only available to derived classes.
Feel free to check out my next blog on OOPS concepts: OOPS - Classes and their relations