What is Object-Oriented Programming?
Object-oriented programming is a programming
paradigm based on the concept of "objects", which can contain data
and code: data in the form of fields, and code, in the form of procedures. A
feature of objects is that an object's own procedures can access and often
modify the data fields of itself.
Object Oriented Programming is considered as a
design methodology for building non-rigid software. In OOPS, every logic is
written to get our work done, but represented in form of Objects. OOP allows us
to break our problems into small unit of work that is represented via objects
and their functions. We build functions around objects.
There are mainly four pillars (features) of OOP.
If all of these four features are presented in programming, the programming is
called perfect Object Oriented Programming.
- Abstraction
- Encapsulation
- Inheritance
- Polymorphism
disadvantages of object-oriented
programming include:
- Steep learning curve: The thought process involved in object-oriented
programming may not be natural for some people, and it can take time to
get used to it. It is complex to create programs based on interaction of
objects. Some of the key programming techniques, such as inheritance and
polymorphism, can be challenging to comprehend initially.
- Larger program size: Object-oriented programs typically involve
more lines of code than procedural programs.
- Slower programs: Object-oriented programs are typically
slower than procedure-based programs, as they typically require more
instructions to be executed.
- Not suitable for all types of problems: There are problems that lend themselves well
to functional-programming style, logic-programming style, or
procedure-based programming style, and applying object-oriented
programming in those situations will not result in efficient programs.
Class:
A class in C++ is the building block, that
leads to Object-Oriented programming. It is a user-defined data type, which
holds its own data members and member functions, which can be accessed and used
by creating an instance of that class. A C++ class is like a blueprint for an
object.
class Geeks
{
// Access specifier
public:
// Data Members
string geekname;
// Member Functions()
void
printname()
{
cout << "Geekname
is: " << geekname;
}
};
CLASS
AND STRUCTURE:
Class |
Structure |
Classes are of reference types. |
Structs are of value types. |
All the reference types are allocated on heap memory. |
All the value types are allocated on stack memory. |
Allocation of large reference type is cheaper than allocation of large
value type. |
Allocation and de-allocation is cheaper in value type as compare to
reference type. |
Class has limitless features. |
Struct has limited features. |
Class is generally used in large programs. |
Struct are used in small programs. |
Classes can contain constructor or destructor. |
Structure does not contain parameter less constructor or destructor,
but can contain Parameterized constructor or static constructor. |
Classes used new keyword for creating instances. |
Struct can create an instance, with or without new keyword. |
A Class can inherit from another class. |
A Struct is not allowed to inherit from another struct or class. |
The data member of a class can be protected. |
The data member of struct can’t be protected. |
Function member of the class can be virtual or abstract. |
Function member of the struct cannot be virtual or abstract. |
Two variable of class can contain the reference of the same object and
any operation on one variable can affect another variable. |
Each variable in struct contains its own copy of data(except in ref
and out parameter variable) and any operation on one variable can not effect
another variable. |
Access modifiers:
Access modifier are used to implement an important
aspect of Object-Oriented Programming known as Data Hiding.
There are 3 types of access modifiers available in
C++:
1.
Public
2.
Private
3.
Protected
1. Public: All the class members
declared under the public specifier will be available to everyone. The data
members and member functions declared as public can be accessed by other
classes and functions too. The public members of a class can be accessed from
anywhere in the program using the direct member access operator (.) with the object
of that class.
class Circle
{
public:
double
radius;
double
compute_area()
{
return
3.14*radius*radius;
}
};
2. Private: The class members declared
as private can be accessed only by the member functions inside
the class. They are not allowed to be accessed directly by any object or
function outside the class. Only the member functions or the friend functions are allowed
to access the private data members of a class.
class Circle
{
// private data member
private:
double
radius;
// public member function
public:
double
compute_area()
{
// member function can access private
// data
member radius
return
3.14*radius*radius;
}
};
3. Protected: Protected access modifier is
similar to private access modifier in the sense that it can’t be accessed
outside of it’s class unless with the help of friend class, the difference is
that the class members declared as Protected can be accessed by any subclass(derived
class) of that class as well.
#include <bits/stdc++.h>
using namespace
std;
// base class
class Parent
{
// protected data members
protected:
int
id_protected;
};
// sub class or derived class from public base class
class Child
: public Parent
{
public:
void
setId(int
id)
{
// Child class is able
to access the inherited
// protected data
members of base class
id_protected
= id;
}
void
displayId()
{
cout
<< "id_protected
is: " <<
id_protected <<
endl;
}
};
// main function
int main()
{
Child
obj1;
// member function of the derived
class can
// access the protected data members
of the base class
obj1.setId(81);
obj1.displayId();
return
0;
}
Output:
id_protected is: 81
Friend Class A friend class can access
private and protected members of other class in which it is declared as friend.
It is sometimes useful to allow a particular class to access private members of
other class. For example, a LinkedList class may be allowed to access private
members of Node.
class Node
{
private:
int
key;
Node* next;
/* Other members of Node Class */
// Now class LinkedList can
// access private members of Node
friend
class LinkedList;
};
Friend Function Like friend class, a
friend function can be given a special grant to access private and protected
members. A friend function can be:
a) A member of another class
b) A global function
class Node
{
private:
int
key;
Node*
next;
/* Other members of Node Class */
friend
int LinkedList::search();
// Only search() of linkedList
// can access internal members
};
Friend class:
#include
<iostream>
class A {
private:
int a;
public:
A() { a =
0; }
friend
class B; // Friend Class
};
class B {
private:
int b;
public:
void
showA(A& x)
{
// Since B is friend of A, it can access
// private members of A
std::cout << "A::a=" << x.a;
}
};
int main()
{
A a;
B b;
b.showA(a);
return 0;
}
Output:
A::a=0
Friend function:
#include
<iostream>
class B;
class A {
public:
void
showB(B&);
};
class B {
private:
int b;
public:
B() { b =
0; }
friend
void A::showB(B& x); // Friend function
};
void A::showB(B& x)
{
// Since
showB() is friend of B, it can
// access
private members of B
std::cout
<< "B::b = " << x.b;
}
int main()
{
A a;
B x;
a.showB(x);
return 0;
}
Output:
B::b = 0
What is constructor?
A constructor is a special type of member function of a class which initializes
objects of a class. In C++, Constructor is automatically called when
object(instance of class) create. It is special member function of the class
because it does not have any return type.
- Constructor has same name as the class itself
- Constructors don’t have return type
- A constructor is automatically called when an object is created.
- It must be placed in public section of class.
- If we do not specify a constructor, C++ compiler generates a
default constructor for object (expects no parameters and has an empty
body).
1. Default Constructors: Default
constructor is the constructor which doesn’t take any argument. It has no
parameters.
#include
<iostream>
using namespace std;
class construct
{
public:
int a, b;
// Default
Constructor
construct()
{
a = 10;
b = 20;
}
};
int main()
{
// Default
constructor called automatically
// when
the object is created
construct
c;
cout
<< "a: " << c.a << endl
<< "b: " << c.b;
return 1;
}
Output:
a: 10
b: 20
2. Parameterized Constructors: It is possible to
pass arguments to constructors. Typically, these arguments help initialize an
object when it is created. To create a parameterized constructor, simply add
parameters to it the way you would to any other function. When you define the
constructor’s body, use the parameters to initialize the object.
#include
<iostream>
using namespace std;
class Point
{
private:
int x, y;
public:
//
Parameterized Constructor
Point(int
x1, int y1)
{
x = x1;
y = y1;
}
int getX()
{
return x;
}
int getY()
{
return y;
}
};
int main()
{
//
Constructor called
Point
p1(10, 15);
// Access
values assigned by constructor
cout
<< "p1.x = " << p1.getX() << ", p1.y = "
<< p1.getY();
return 0;
}
Output:
p1.x = 10, p1.y = 15
When an object is declared in a parameterized
constructor, the initial values have to be passed as arguments to the
constructor function. The normal way of object declaration may not work. The
constructors can be called explicitly or implicitly.
Example e =
Example(0, 50); // Explicit call
Example e(0, 50); // Implicit call
- Uses of Parameterized constructor:
- It is used to initialize the various data elements of different
objects with different values when they are created.
- It is used to overload constructors.
- Can we have more than one constructor in a class?
Yes, It is called Constructor Overloading.
3. Copy Constructor:
A copy constructor is a member function which
initializes an object using another object of the same class. Detailed article
on Copy Constructor.
Whenever we define one or more non-default
constructors( with parameters ) for a class, a default constructor( without
parameters ) should also be explicitly defined as the compiler will not provide
a default constructor in this case. However, it is not necessary but it’s
considered to be the best practice to always define a default constructor.
#include
"iostream"
using namespace std;
class point
{
private:
double x, y;
public:
// Non-default
Constructor &
// default
Constructor
point (double px,
double py)
{
x = px, y
= py;
}
};
int main(void)
{
// Define an
array of size
// 10 & of
type point
// This line will
cause error
point a[10];
// Remove above
line and program
// will compile
without error
point b =
point(5, 6);
}
Output:
Error: point (double px,
double py): expects 2 arguments, 0 provided
Shallow Copy:
In shallow copy, an object is created by
simply copying the data of all variables of the original object. This works
well if none of the variables of the object are defined in the heap section of memory. If some variables are dynamically allocated memory
from heap section, then copied object variable will also reference then same
memory location.
This will create ambiguity and run-time errors dangling pointer. Since both
objects will reference to the same memory location, then change made by one
will reflect those change in another object as well. Since we wanted to create
a replica of the object, this purpose will not be filled by Shallow copy.
Note: C++ compiler
implicitly creates a copy constructor and overloads assignment operator in order to perform shallow copy at
compile time.
Shallow Copy of object if some
variables are defined in heap memory, then:
Deep Copy:
In Deep copy, an
object is created by copying data of all variables and it also allocates
similar memory resources with the same value to the object. In order to perform
Deep copy, we need to explicitly define the copy constructor and assign dynamic
memory as well if required. Also, it is required to dynamically allocate memory
to the variables in the other constructors, as well.
DIFFERENCE BETWEEN CONSTRUCTOR AND MEMBER FUNCTION:
Constructor name must be same as class name but
functions cannot have same name as class name. Constructor does not have return
type whereas functions must have. Constructors are invoked at the time of object
creation automatically and cannot be called explicitly but functions are called
explicitly using class objects.
VIRTUAL CONSTRUCTOR:
The virtual mechanism works only when we have
a base class pointer to a derived class object. In C++, the constructor
cannot be virtual, because when a constructor of a class is executed there is
no virtual table in the memory, means no virtual pointer defined yet.
#include<iostream>
using namespace std;
class b {
public:
b()
{
cout<<"Constructing base \n";
}
virtual ~b() {
cout<<"Destructing base \n";
}
};
class d: public b {
public:
d()
{
cout<<"Constructing derived \n";
}
~d() {
cout<<"Destructing derived \n";
}
};
int main(void) {
d *derived
= new d();
b *bptr =
derived;
delete
bptr;
return 0;
}
Output
Constructing base
Constructing derived
Destructing derived
Destructing base
Destructor:
·
Destructor function is automatically invoked when
the objects are destroyed.
·
It cannot be declared static or const.
·
The destructor does not have arguments.
·
It has no return type not even void.
·
An object of a class with a Destructor cannot
become a member of the union.
·
A destructor should be declared in the public
section of the class.
·
The programmer cannot access the address of
destructor.
How are destructors different from a normal member
function?
Destructors have same name as the class preceded
by a tilde (~). Destructors don’t take any argument and don’t return anything.
#include
<iostream>
using namespace std;
class Employee
{
public:
Employee()
{
cout<<"Constructor Invoked"<<endl;
}
~Employee()
{
cout<<"Destructor Invoked"<<endl;
}
};
int main(void)
{
Employee
e1; //creating an object of Employee
Employee
e2; //creating an object of Employee
return 0;
}
OUTPUT:
Constructor Invoked
Constructor Invoked
Destructor Invoked
Destructor Invoked
CLASS AND OBJECT REAL WORLD EXAMPLE:
Consider an ATM. An ATM is a class. It’s machine
which is pretty much useless until you insert your debit card. After you insert
your debit card, the machine has information about you and your bank account
and the balance in it, so at this point it is an object. You have used a class
and created an object, now you can perform operations on it like withdrawal of
money or checking you balance or getting statement of your account, these
operations will be methods belonging to that class (ATM) but you cannot use
them until you create an object out of it.
And when you did perform whatever operation you
wanted to perform and clicked exit/cancel and removed your card, you just
destroyed the object. Now it is not an object, it has methods and all (the
functions an ATM can perform) but you cannot use them until you insert your
card again and create an object.
STATIC KEYWORD:
The static keyword in Java is used for memory
management mainly. We can apply static keyword with variables, methods, blocks and nested classes. The static keyword belongs to
the class than an instance of the class.
The static can be:
1.
Variable (also known as a class variable)
2.
Method (also known as a class method)
3.
Block
4.
Nested class
Virtual Function in C++
A virtual function is a member function which is
declared within a base class and is re-defined(Overridden) by a derived class.
When you refer to a derived class object using a pointer or a reference to the
base class, you can call a virtual function for that object and execute the
derived class’s version of the function.
·
Virtual functions ensure that the correct function
is called for an object, regardless of the type of reference (or pointer) used
for function call.
·
They are mainly used to achieve Runtime polymorphism
·
Functions are declared with a virtual keyword
in base class.
·
The resolving of function call is done at Run-time.
Rules for Virtual Functions:
Want to learn from the best curated videos and practice problems, check out
the C++ Foundation Course for Basic to
Advanced C++ and C++ STL Course for
foundation plus STL. To complete your preparation from learning a
language to DS Algo and many more, please refer Complete Interview Preparation
Course.
1.
Virtual functions cannot be static.
2.
A virtual function can be a friend function of
another class.
3.
Virtual functions should be accessed using pointer
or reference of base class type to achieve run time polymorphism.
4.
The prototype of virtual functions should be the
same in the base as well as derived class.
5.
They are always defined in the base class and
overridden in a derived class. It is not mandatory for the derived class to
override (or re-define the virtual function), in that case, the base class
version of the function is used.
6.
A class may have virtual destructor but it
cannot have a virtual constructor.
Compile-time(early binding) VS run-time(late
binding) behavior of Virtual Functions
#include <iostream>
using namespace
std;
class base
{
public:
virtual
void print()
{
cout << "print
base class" << endl;
}
void
show()
{
cout << "show
base class" << endl;
}
};
class derived
: public base
{
public:
void
print()
{
cout << "print
derived class" << endl;
}
void
show()
{
cout << "show
derived class" << endl;
}
};
int main()
{
base* bptr;
derived d;
bptr = &d;
// virtual function, binded at
runtime
bptr->print();
// Non-virtual function, binded at
compile time
bptr->show();
}
Output:
print derived class
show base class
abstract classes and these abstract
classes should not be confused with data abstraction which is a concept of
keeping implementation details separate from associated data.
A class is made abstract by declaring at least one
of its functions as pure virtual function. A pure virtual
function is specified by placing "= 0" in its declaration as follows
−
The purpose of an abstract class (often
referred to as an ABC) is to provide an appropriate base class from which other
classes can inherit. Abstract classes cannot be used to instantiate objects and
serves only as an interface. Attempting to instantiate an object of
an abstract class causes a compilation error.
Thus, if a subclass of an ABC needs to be
instantiated, it has to implement each of the virtual functions, which means
that it supports the interface declared by the ABC. Failure to override a pure
virtual function in a derived class, then attempting to instantiate objects of
that class, is a compilation error.
Classes that can be used to instantiate objects are
called concrete classes.
#include
<iostream>
using namespace std;
// Base class
class Shape {
public:
//
pure virtual function providing interface framework.
virtual int getArea() = 0;
void setWidth(int w) {
width = w;
}
void setHeight(int h) {
height = h;
}
protected:
int
width;
int
height;
};
// Derived classes
class Rectangle: public
Shape {
public:
int
getArea() {
return (width * height);
}
};
class Triangle: public
Shape {
public:
int
getArea() {
return (width * height)/2;
}
};
int main(void) {
Rectangle
Rect;
Triangle
Tri;
Rect.setWidth(5);
Rect.setHeight(7);
// Print
the area of the object.
cout
<< "Total Rectangle area: " << Rect.getArea() <<
endl;
Tri.setWidth(5);
Tri.setHeight(7);
// Print
the area of the object.
cout
<< "Total Triangle area: " << Tri.getArea() <<
endl;
return 0;
}
Total Rectangle area: 35
Total Triangle area: 17
final specifier in C++ 11:
Sometimes you don’t want to allow derived class to override the base class’
virtual function. C++ 11 allows built-in facility to prevent overriding
of virtual function using final specifier.
#include
<iostream>
class Base final
{
};
class Derived : public
Base
{
};
int main()
{
Derived d;
return 0;
}
prog.cpp:6:7: error:
cannot derive from ‘final’ base ‘Base’ in derived type ‘Derived’
class Derived :
public Base
^
The explicit keyword in :
C++ is used to mark constructors to not implicitly
convert types. For example, if you have a class Foo −
class Foo
{
public:
Foo(int
n); // allocates n
bytes to the Foo object
Foo(const
char *p);
// initialize object with char *p
};
Now if
you try
Foo mystring = 'x';
The char 'x' is implicitly converted to int and
then will call the Foo(int) constructor. But this is not what was intended. So
to prevent such conditions and make the code less error-prone, define the
constructor as explicit −
Example
class Foo
{
public:
explicit
Foo (int
n); //allocate n bytes
Foo(const
char *p);
// initialize with string p
};
this is a keyword that refers
to the current instance of the class. There can be 3 main usage of this keyword
in C++.
·
It can be used to pass current object as a
parameter to another method.
·
It can be used to refer current class
instance variable.
·
It can be used to declare indexers.
The new operator:
is an
operator which denotes a request for memory allocation on the Heap. If
sufficient memory is available, new operator initializes the memory and returns
the address of the newly allocated and initialized memory to the pointer
variable. When you create an object of class using new keyword(normal new).
·
The memory for the object is allocated using
operator new from heap.
·
The constructor of the class is invoked to properly
initialize this memory.
car *p = new
car("Honda", 2017); //OBJECT
Operator new
Operator new is a function that
allocates raw memory and conceptually a bit similar to malloc().
·
It is the mechanism of overriding the default heap
allocation logic.
·
It doesn’t initializes the memory i.e constructor
is not called. However, after our overloaded new returns, the compiler then
automatically calls the constructor also as applicable.
·
It’s also possible to overload operator new either
globally, or for a specific class
void *operator new(size_t size)
{
cout << "new operator overloaded" << endl;
void *p = malloc(size);
return p;
}
const keyword is attached with any
method(), variable, pointer variable, and with the
object of a class it prevents that specific object/method()/variable to
modify its data items value.
·
The const
variable cannot be left un-initialized at the time of the assignment.
·
It cannot be assigned value anywhere in the
program.
·
Explicit value needed to be provided to the
constant variable at the time of declaration of the constant variable.
#include <iostream>
using namespace
std;
// Driver Code
int main()
{
// const int x; CTE error
// x = 9; CTE error
const
int y
= 10;
cout
<< y;
return
0;
}
Output:
10
Super is a keyword
It is used inside a sub-class method definition to
call a method defined in the super class. Private methods of the
super-class cannot be called. Only public and protected methods can be called
by the super keyword. It is also used by class constructors to
invoke constructors of its parent class.
C++ doesn't have a super or base keyword to designate
"the base class", like C# and Java do. One reason for this
is that C++ supports multiple inheritance, which would make such a
keyword ambiguous.
FEATURES OF OOP:
POLYMORPHISM:
The word polymorphism means having many forms. In
simple words, we can define polymorphism as the ability of a message to be
displayed in more than one form. A real-life example of polymorphism, a person
at the same time can have different characteristics. Like a man at the same
time is a father, a husband, an employee. So the same person posses different
behavior in different situations. This is called polymorphism. Polymorphism is
considered as one of the important features of Object Oriented Programming.
- Compile time Polymorphism
- Runtime Polymorphism
- Compile time polymorphism: This type of polymorphism is achieved
by function overloading or operator overloading.
- Function Overloading: When there are multiple functions with
same name but different parameters then these functions are said to
be overloaded. Functions can be overloaded by change
in number of arguments or/and change in type of
arguments.
#include <bits/stdc++.h>
using namespace std;
class Geeks
{
public:
// function with 1 int parameter
void func(int x)
{
cout <<
"value of x is " << x << endl;
}
// function with same name but 1
double parameter
void func(double x)
{
cout <<
"value of x is " << x << endl;
}
// function with same name and 2 int
parameters
void func(int x, int y)
{
cout <<
"value of x and y is " << x << ", " << y
<< endl;
}
};
int main() {
Geeks obj1;
// Which function is called will
depend on the parameters passed
// The first 'func' is called
obj1.func(7);
// The second 'func' is called
obj1.func(9.132);
// The third 'func' is called
obj1.func(85,64);
return 0;
}
Output:
value of x is 7
value of x is 9.132
value of x and y is 85, 64
·
Operator Overloading: C++ also
provide option to overload operators. For example, we can make the operator
(‘+’) for string class to concatenate two strings. We know that this is the
addition operator whose task is to add two operands. So a single operator ‘+’
when placed between integer operands , adds them and when placed between string
operands, concatenates them.
Example:
#include<iostream>
using namespace std;
class Complex {
private:
int real,
imag;
public:
Complex(int r = 0, int i =0) {real = r; imag = i;}
// This is
automatically called when '+' is used with
// between
two Complex objects
Complex
operator + (Complex const &obj) {
Complex res;
res.real = real + obj.real;
res.imag = imag + obj.imag;
return res;
}
void
print() { cout << real << " + i" << imag <<
endl; }
};
int main()
{
Complex
c1(10, 5), c2(2, 4);
Complex c3
= c1 + c2; // An example call to "operator+"
c3.print();
}
Output:
12 + i9
Runtime polymorphism: This type of
polymorphism is achieved by Function Overriding.
- Function overriding on the other hand
occurs when a derived class has a definition for one of the member
functions of the base class. That base function is said to be overridden.
#include <bits/stdc++.h>
using namespace std;
class base
{
public:
virtual void print ()
{ cout<< "print base
class" <<endl; }
void show ()
{ cout<< "show base
class" <<endl; }
};
class derived:public base
{
public:
void print () //print () is already
virtual function in derived class, we could also declared as virtual void print
() explicitly
{ cout<< "print derived
class" <<endl; }
void show ()
{ cout<< "show derived
class" <<endl; }
};
//main function
int main()
{
base *bptr;
derived d;
bptr = &d;
//virtual function, binded at runtime
(Runtime polymorphism)
bptr->print();
// Non-virtual function, binded at
compile time
bptr->show();
return 0;
}
Output:
print derived class
show base class
INHERITANCE:
he capability of a class to
derive properties and characteristics from another class is called Inheritance.
Inheritance is one of the most important feature of Object Oriented
Programming.
Sub Class: The class that inherits properties from another class is
called Sub class or Derived Class.
Super Class:The class whose properties are inherited by sub class is
called Base Class or Super class.
Types
of Inheritance in C++
1.
Single Inheritance: In single inheritance,
a class is allowed to inherit from only one class. i.e. one sub class is
inherited by one base class only.
Syntax:
class subclass_name : access_mode base_class
{
//body of subclass
};
// C++ program to
explain
// Single inheritance
#include
<iostream>
using namespace std;
// base class
class Vehicle {
public:
Vehicle()
{
cout << "This is a Vehicle" << endl;
}
};
// sub class derived
from a single base classes
class Car: public
Vehicle{
};
// main function
int main()
{
//
creating object of sub class will
// invoke
the constructor of base classes
Car obj;
return 0;
}
Output
This is a Vehicle
2.
Multiple Inheritance: Multiple
Inheritance is a feature of C++ where a class can inherit from more than one
classes. i.e one sub class is inherited from more than one base
classes.
Syntax:
class subclass_name : access_mode base_class1, access_mode base_class2, ....
{
//body of subclass
};
Here, the
number of base classes will be separated by a comma (‘, ‘) and access mode for
every base class must be specified.
#include
<iostream>
using namespace std;
// first base class
class Vehicle {
public:
Vehicle()
{
cout << "This is a Vehicle" << endl;
}
};
// second base class
class FourWheeler {
public:
FourWheeler()
{
cout << "This is a 4 wheeler Vehicle" << endl;
}
};
// sub class derived
from two base classes
class Car: public
Vehicle, public FourWheeler {
};
// main function
int main()
{
//
creating object of sub class will
// invoke
the constructor of base classes
Car obj;
return 0;
}
Output
This is a Vehicle
This is a 4 wheeler
Vehicle
Please visit this link to learn multiple inheritance in details.
3. Multilevel Inheritance: In this type of inheritance, a derived class is created
from another derived class.
// C++ program to
implement
// Multilevel
Inheritance
#include
<iostream>
using namespace std;
// base class
class Vehicle
{
public:
Vehicle()
{
cout << "This is a Vehicle" << endl;
}
};
// first sub_class
derived from class vehicle
class fourWheeler:
public Vehicle
{ public:
fourWheeler()
{
cout<<"Objects with 4 wheels are vehicles"<<endl;
}
};
// sub class derived
from the derived base class fourWheeler
class Car: public
fourWheeler{
public:
Car()
{
cout<<"Car has 4 Wheels"<<endl;
}
};
// main function
int main()
{
//creating
object of sub class will
//invoke
the constructor of base classes
Car obj;
return 0;
}
Output
This is a Vehicle
Objects with 4 wheels
are vehicles
Car has 4 Wheels
4.
Hierarchical Inheritance: In this
type of inheritance, more than one sub class is inherited from a single base
class. i.e. more than one derived class is created from a single base class.
#include
<iostream>
using namespace std;
// base class
class Vehicle
{
public:
Vehicle()
{
cout << "This is a Vehicle" << endl;
}
};
// first sub class
class Car: public
Vehicle
{
};
// second sub class
class Bus: public
Vehicle
{
};
// main function
int main()
{
//
creating object of sub class will
// invoke
the constructor of base class
Car obj1;
Bus obj2;
return 0;
}
Output
This is a Vehicle
This is a Vehicle
5. Hybrid (Virtual) Inheritance: Hybrid Inheritance is implemented by combining more than
one type of inheritance. For example: Combining Hierarchical inheritance and
Multiple Inheritance.
Below image shows the combination of hierarchical and multiple inheritance:
#include
<iostream>
using namespace std;
// base class
class Vehicle
{
public:
Vehicle()
{
cout << "This is a Vehicle" << endl;
}
};
//base class
class Fare
{
public:
Fare()
{
cout<<"Fare of Vehicle\n";
}
};
// first sub class
class Car: public
Vehicle
{
};
// second sub class
class Bus: public
Vehicle, public Fare
{
};
// main function
int main()
{
//
creating object of sub class will
// invoke
the constructor of base class
Bus obj2;
return 0;
}
Output
This is a Vehicle
Fare of Vehicle
6. A special case of hybrid inheritance : Multipath inheritance:
A derived class with two base classes and these two base classes have one
common base class is called multipath inheritance. An ambiguity can arrise in
this type of inheritance.
#include <conio.h>
#include <iostream.h>
class ClassA {
public:
int a;
};
class ClassB : public ClassA {
public:
int b;
};
class ClassC : public ClassA {
public:
int c;
};
class ClassD : public ClassB, public ClassC {
public:
int d;
};
void main()
{
ClassD obj;
// obj.a = 10;
//Statement 1, Error
// obj.a = 100;
//Statement 2, Error
obj.ClassB::a = 10; // Statement 3
obj.ClassC::a = 100; // Statement 4
obj.b = 20;
obj.c = 30;
obj.d = 40;
cout << "\n A from ClassB
: " << obj.ClassB::a;
cout << "\n A from ClassC
: " << obj.ClassC::a;
cout << "\n B : "
<< obj.b;
cout << "\n C : "
<< obj.c;
cout << "\n D : "
<< obj.d;
}
Output:
A from ClassB : 10
A from ClassC : 100
B : 20
C : 30
D : 40
·
In the above example, both ClassB &
ClassC inherit ClassA, they both have single copy of ClassA. However ClassD
inherit both ClassB & ClassC, therefore ClassD have two copies of ClassA,
one from ClassB and another from ClassC.
If we need to access the data member a of ClassA through the object of ClassD,
we must specify the path from which a will be accessed, whether it is from
ClassB or ClassC, bco’z compiler can’t differentiate between two copies of
ClassA in ClassD.
There are 2 ways to avoid this ambiguity:
Avoiding ambiguity using scope
resolution operator:
Using scope resolution operator we can manually specify the path from which
data member a will be accessed, as shown in statement 3 and 4, in the above
example.
|
#include<iostream.h>
#include<conio.h>
class ClassA
{
public:
int a;
};
class ClassB : virtual public ClassA
{
public:
int b;
};
class ClassC : virtual public ClassA
{
public:
int c;
};
class ClassD : public ClassB, public ClassC
{
public:
int d;
};
void
main()
{
ClassD obj;
obj.a = 10; //Statement 3
obj.a = 100; //Statement 4
obj.b = 20;
obj.c = 30;
obj.d = 40;
cout<< "\n A : "<< obj.a;
cout<< "\n B : "<< obj.b;
cout<< "\n C : "<< obj.c;
cout<< "\n D : "<< obj.d;
}
Output:
A : 100
B : 20
C : 30
D : 40
Data encapsulation:
It is a mechanism of bundling the data, and the
functions that use them and data abstraction is a mechanism of
exposing only the interfaces and hiding the implementation details from the
user. Encapsulation also lead to data abstraction or hiding. As using
encapsulation also hides the data. In the above example the data of any of the
section like sales, finance or accounts is hidden from any other section.
A primitive data type :
specifies the size and type of variable values, and it has no additional
methods. Eg int, long, double, float, etc.
Array is not a primitive data type.
Binding:
refers to
the process of converting identifiers (such as variable and performance names)
into addresses. Binding is done for each variable and functions. For functions,
it means that matching the call with the right function definition by the
compiler. It takes place either at compile time or at runtime.
Early Binding (compile-time time polymorphism) As the name
indicates, compiler (or linker) directly associate an address to the function
call. It replaces the call with a machine language instruction that tells the
mainframe to leap to the address of the function.
#include<iostream>
using namespace std;
class Base
{
public:
void
show() { cout<<" In Base \n"; }
};
class Derived: public
Base
{
public:
void
show() { cout<<"In Derived \n"; }
};
int main(void)
{
Base *bp =
new Derived;
// The
function call decided at
// compile
time (compiler sees type
// of
pointer and calls base class
//
function.
bp->show();
return 0;
}
Output:
In Base
Late Binding : (Run time polymorphism) In this,
the compiler adds code that identifies the kind of object at runtime then
matches the call with the right function definition (Refer this for
details). This can be achieved by declaring a virtual function.
#include<iostream>
using namespace std;
class Base
{
public:
virtual
void show() { cout<<" In Base \n"; }
};
class Derived: public
Base
{
public:
void
show() { cout<<"In Derived \n"; }
};
int main(void)
{
Base *bp =
new Derived;
bp->show(); // RUN-TIME POLYMORPHISM
return 0;
}
Output:
In Derived
Default access modifier private
Instances made for abstract class is 0.
Garbage collection:
is the process of managing memory, automatically.
It finds the unused objects (that are no longer used by the program) and delete
or remove them to free up the memory. The garbage
collection mechanism uses several GC algorithms. The most popular
algorithm that is used is Mark and Sweep.
The heap is a part of memory where objects live.
It's the only part of memory that involved in the garbage collection process.
It is also known as garbage collectible heap. All the garbage
collection makes sure that the heap has as much free space as possible. The
function of the garbage collector is to find and delete the objects that cannot
be reached.
Important Points About Garbage Collector
·
It is controlled by a thread known as Garbage
Collector.
·
Java provides two methods System.gc() and Runtime.gc() that
sends request to the JVM for garbage collection. Remember, it is not necessary
that garbage collection will happen.
·
Java programmer are free from memory management. We
cannot force the garbage collector to collect the garbage, it depends on the
JVM.
·
If the Heap Memory is full, the JVM will not allow
to create a new object and shows an error java.lang.OutOfMemoryError.
·
When garbage collector removes object from the
memory, first, the garbage collector thread calls the finalize() method of that
object and then remove.
Exception:
An exception is a problem that arises
during the execution of a program. A C++ exception is a response to an
exceptional circumstance that arises while a program is running, such as an
attempt to divide by zero.
Exceptions provide a way to transfer
control from one part of a program to another. C++ exception handling is built
upon three keywords: try, catch, and throw.
·
throw − A
program throws an exception when a problem shows up. This is done using a throw keyword.
·
catch − A
program catches an exception with an exception handler at the place in a
program where you want to handle the problem. The catch keyword
indicates the catching of an exception.
·
try −
A try block identifies a block of code for which particular
exceptions will be activated. It's followed by one or more catch blocks.
Assuming a block will raise an
exception, a method catches an exception using a combination of the try and catch keywords.
A try/catch block is placed around the code that might generate an exception.
Code within a try/catch block is referred to as protected code, and the syntax
for using try/catch as follows −
try {
// protected code
} catch( ExceptionName e1 ) {
// catch block
} catch( ExceptionName e2 ) {
// catch block
} catch( ExceptionName eN ) {
// catch block
}
You can list down multiple catch statements
to catch different type of exceptions in case your try block
raises more than one exception in different situations.
Throwing Exceptions
Exceptions can be thrown anywhere
within a code block using throw statement. The operand of the
throw statement determines a type for the exception and can be any expression
and the type of the result of the expression determines the type of exception
thrown.
Following is an example of throwing an
exception when dividing by zero condition occurs −
double division(int a, int b) {
if( b == 0 ) {
throw "Division by zero condition!";
}
return (a/b);
}
Catching Exceptions
The catch block
following the try block catches any exception. You can specify
what type of exception you want to catch and this is determined by the
exception declaration that appears in parentheses following the keyword catch.
try {
// protected code
} catch( ExceptionName e ) {
// code to handle ExceptionName exception
}
Above code will catch an exception
of ExceptionName type. If you want to specify that a catch
block should handle any type of exception that is thrown in a try block, you
must put an ellipsis, ..., between the parentheses enclosing the exception
declaration as follows −
try {
// protected code
} catch(...) {
// code to handle any exception
}
The following is an example, which
throws a division by zero exception and we catch it in catch block.
#include <iostream>
using namespace
std;
double division(int
a, int
b) {
if(
b == 0
) {
throw
"Division by zero condition!";
}
return
(a/b);
}
int main
() {
int
x = 50;
int
y = 0;
double
z = 0;
try
{
z
= division(x,
y);
cout
<< z
<< endl;
} catch
(const char*
msg) {
cerr
<< msg
<< endl;
}
return
0;
}
condition ?
value_if_true : value_if_false
The statement evaluates
to value_if_true if condition is met,
and value_if_false otherwise.
inta
=10,
b
=20,
c
;
c
=(
a
<b
)?
a
:b
;
printf("%d",c
);
Deadlock is a situation
where a set of processes are blocked because each process is holding a resource
and waiting for another resource acquired by some other process.
Consider an example when two trains are coming toward each other on the same
track and there is only one track, none of the trains can move once they are in
front of each other. A similar situation occurs in operating systems when there
are two or more processes that hold some resources and wait for resources held
by other(s). For example, in the below diagram, Process 1 is holding Resource 1
and waiting for resource 2 which is acquired by process 2, and process 2 is
waiting for resource 1.
Deadlock can arise if the following
four conditions hold simultaneously (Necessary Conditions)
Mutual Exclusion: One or more than one resource are non-shareable
(Only one process can use at a time)
Hold and Wait: A process is holding at least one
resource and waiting for resources.
No Preemption: A resource cannot be taken from a process
unless the process releases the resource.
Circular Wait: A set of processes are waiting for each other
in circular form.
Methods for handling deadlock
There are three ways to handle deadlock
1) Deadlock prevention or avoidance: The idea is to not let the system into a
deadlock state.
One can zoom into each category individually, Prevention is done by negating
one of above mentioned necessary conditions for deadlock.
Avoidance is kind of futuristic in nature. By using strategy of “Avoidance”, we
have to make an assumption. We need to ensure that all information about
resources which process will need are known to us prior to execution of the
process. We use Banker’s algorithm (Which is in-turn a gift from Dijkstra) in
order to avoid deadlock.
2) Deadlock detection and recovery: Let deadlock
occur, then do preemption to handle it once occurred.
3) Ignore the problem altogether: If deadlock is
very rare, then let it happen and reboot the system. This is the approach that
both Windows and UNIX take.
Comments
Post a Comment