Section 12: Introduction to OOPS
Principles of Object Orientation
- Abstraction
- Encapsulation/Data Hiding
- Inheritance
- Polymorphism
Abstraction
- When we don't know the internal details, that is nothing but abstraction.
- We just need names of functions; we don't see the implementation of functions as well as data (data is hidden).
- We only know function details when we are writing them, not when we are using them.
- Example: Without knowing how the
printfis working we have used it many times, so that is abstraction for us. - Classes help us achieve abstraction.
Encapsulation
- We hide the data and make the functions visible, and we put things together at one place.
- Data and functions are together; a Class helps keep the data and the functions together. That is encapsulation.
- Along with this, in classes, we make data as private. This is not for security; it's for avoiding mishandling.
- We make it private and functions public. We hide the data and show functions.
- Data hiding comes as a part of encapsulation.
Just like Abstraction and Encapsulation are interrelated, Inheritance and Polymorphism are also interrelated.
Inheritance
- Suppose I want another class in which I want all these features plus extra features. I should be able to inherit, borrow all these features from an existing class. This is inheritance.
classDiagram
class BaseClass {
+ExistingFeatures
}
class DerivedClass {
+ExtraFeatures
}
BaseClass <|-- DerivedClass : Inherits
Polymorphism
- We can define polymorphism as the ability of a message to be displayed in more than one form.
-
A real-life example: A person at the same time can have different characteristics. Like a man at the same time is a father, a husband, an employee.
-
Example: If we want to learn driving, we will learn to drive a "car", not specifically a BMW or Suzuki or Toyota. If we learn one, we can drive all cars.
- The way it runs is different, the way it drives is different. That's polymorphism.
- With the help of inheritance, we achieve polymorphism.
Class
- Class is basically a classification. Students, employees, cars, etc., are all classifications or a class.
- Classification is based on some criteria/property or the common things that we find in them.
- Class is a definition/blueprint/design and Object is an instance.
- Our class will contain data and functions.
- Data is called as property.
-
Function is called as behavior.
-
Defining a class is different from creating its object and using it.
- Classes are used for defining user-defined data types so that we can declare the variables of that class type.
- Functions will not occupy any memory space; only data members occupy memory.
- Whatever we write inside the class, by default, it becomes private.
- Dot operator (
.) is used for accessing members of an object.
Class Example:
class Rectangle {
public:
int length;
int breadth;
int area() {
return length * breadth;
}
int perimeter() {
return 2 * (length + breadth);
}
};
int main() {
Rectangle r1;
r1.length = 10;
r1.breadth = 5;
cout << r1.area(); // Output: 50
}
Pointer to an Object in Heap
- We are using a pointer in the example below, but memory is still in stack, not in heap.
- Dot operator (
.): Used for accessing the members of an object using a variable name. - Arrow operator (
->): Used for accessing the members of an object using a pointer on an object. - The arrow (
->) is a de-referencing operator; instead of using*(star), we can use this. - Every pointer takes either 2 or 4 bytes depending on the compiler.
How to create an object in Heap:
- There is no name for the object, but a pointer is pointing onto that one.
- Stack Object:
Rectangle r; - Heap Object:
Rectangle *p = new Rectangle(); - Note: In Java, we cannot create an object in the stack; objects are always created in a heap using
new. But C++ gives us an option whether we want it in the stack or the heap.
graph LR
subgraph Stack
p[Pointer *p]
end
subgraph Heap
obj[Rectangle Object]
end
p -->|Points to| obj
Code Example:
Rectangle r; // Created in Stack
Rectangle *p;
p = new Rectangle; // Created in Heap
p->length = 15;
p->breadth = 10;
cout << p->area(); // Accessing using arrow operator
Data Hiding
- Only the functions should be made public; data members should be made private.
- If data is made public, there are chances it may be mishandled. If mishandling is done, the functions of a class may not give right results, and we cannot rely on such classes.
- As now data members are private, we can't read or change their values directly. So we make functions to do so: Getters (Accessor) and Setters (Mutator).
Code Example:
class Rectangle {
private:
int length;
int breadth;
public:
// Mutator (Setter)
void setLength(int l) {
if(l >= 0)
length = l;
else
length = 0;
}
// Accessor (Getter)
int getLength() {
return length;
}
};
Constructor
- It's philosophically wrong when we create a rectangle object and its length and breadth are garbage/undefined (and we set them later).
- While creating or buying any rectangle object, we also tell what should be its length and breadth.
- So we want the length and breadth to be set at the time of construction of that object.
- A constructor is a function which will be automatically called when the object is constructed.
What is a Constructor?
- A constructor is a function which will have the same name as the class name.
- The constructor will not have any return type.
Different types of Constructors:
- Default Constructor: (Built-in/Compiler provided). If we don't write any, the compiler provides one. It is called automatically when we create an object.
- Non-Parameterized Constructor: (User-defined default).
- Parameterized Constructor.
- Copy Constructor.
Constructor Examples:
class Rectangle {
private:
int length;
int breadth;
public:
// Non-Parameterized Constructor
Rectangle() {
length = 0;
breadth = 0;
}
// Parameterized Constructor
Rectangle(int l, int b) {
setLength(l);
setBreadth(b);
}
// Copy Constructor
Rectangle(Rectangle &r) {
length = r.length;
breadth = r.breadth;
}
};
Problem with Copy Constructor (Shallow Copy)
- The problem with the copy constructor is if there is a direct memory allocation done by an object, then the copy constructor may not create a new memory for it; it will point on the same memory.
- We have to be careful with this type of thing.
Deep Copy Constructor
- We need to copy everything.
- Our copy constructor should create new memory and point to it, instead of just pointing to the memory of the object that passed.
Types of Functions in a Class
- Constructor (Non-Parameterized, Parameterized, Copy)
- Mutators (
setLength,setBreadth) - Accessors (
getLength,getBreadth) - Facilitators (
area,perimeter) - Inspector Function (Enquiry - e.g.,
isSquare(). returns boolean or int). - Destructor
Scope Resolution Operator (::)
- We don't always elaborate functions inside the class. We just write the header/prototype inside, and the functions are elaborated outside the class using the Scope Resolution Operator.
- This shows that the scope of this function is within the class specified.
- Mechanism:
- If we write the function outside, the machine code for that function is separately generated. Calls go to that function and return.
-
If we write the function inside the class, the machine code is replaced at the place of the function call (Inline).
-
In C++, it is good practice to write the function outside using scope resolution unless logic is simple.
Code Example:
class Rectangle {
// ... data members ...
public:
int area(); // Prototype only
};
// Definition outside class
int Rectangle::area() {
return length * breadth;
}
Inline Functions
- The functions which expand in the same line where they are called.
- There is no separate block for that function in machine code; it is pasted/copied at the place of call.
- Automatic: If we define a function inside a class, it is automatically inline.
- Manual: If we write a function outside, we can make it inline by adding the
inlinekeyword.
This Pointer
- How do you refer to the data members of the same class or the same object to avoid name ambiguity?
- We use
this->. thisis a pointer to the current object.
Code Example:
Rectangle(int length, int breadth) {
this->length = length; // this->length refers to data member
this->breadth = breadth; // breadth refers to parameter
}
Structure vs Class
- In C language, structures can only have data members.
- In C++, structures can have data members as well as functions (similar to a class).
| Feature | Class | Structure (struct) |
|---|---|---|
| Default Access | Private | Public |
| Usage | Used for Data Hiding & OOP | Used for grouping public data |
Code Example: