Unit 2 Encapsulation in C
Unit 2 Encapsulation in C
in a company there are different sections like the accounts section, finance
section, sales section etc. The finance section handles all the financial
transactions and keep records of all the data related to finance. Similarly the
sales section handles all the sales related activities and keep records of all
the sales. Now there may arise a situation when for some reason an official
from finance section needs all the data about sales in a particular month. In
this case, he is not allowed to directly access the data of sales section. He
will first have to contact some other officer in the sales section and then
request him to give the particular data. This is what encapsulation is. Here
the data of sales section and the employees that can manipulate them are
wrapped under a single name “sales section”.
NOTE
“Hiding the object details (state and behavior) from the users”
Information Hiding is achieved in Object Oriented Programming
using the following principles,
· All information related to an object is stored within the object
· It is hidden from the outside world
· It can only be manipulated by the object itself
Role of access specifiers in encapsulation
access specifiers plays an important role in implementing encapsulation in
C++. The process of implementing encapsulation can be sub-divided into
two steps:
1. The data members should be labeled as private using
the private access specifiers
2. The member function which manipulates the data members should be
labeled as public using the public access specifier
Public: If a class member is public, it can be used anywhere without the access
restrictions.
Private: if a class member is private, it can be used only by the members and
friends of class.
Protected: if a class member is protected, it can be used only by the members and
friends of class and the members and friends of classes derived from class.
In other words:
C++ supports the properties of encapsulation and data hiding through the
creation of user-defined types, called classes. We already have studied
that a class can contain private, protected and public members. By
default, all items defined in a class are private. For example:
class Box {
public:
double getVolume(void) {
return length * breadth * height;
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
The variables length, breadth, and height are private. This means that they
can be accessed only by other members of the Box class, and not by any
other part of your program. This is one way encapsulation is achieved.
#include<iostream>
class Encapsulation
private:
int x;
public:
// variable x
void set(int a)
{
x =a;
}
// variable x
int get()
{
return x;
}
};
// main function
int main()
Encapsulation obj;
obj.set(5);
cout<<obj.get();
return 0;
Run on IDE
output:
In the above program the variable x is made private. This variable can be
accessed and manipulated only using the functions get() and set() which are
present inside the class. Thus we can say that here, the variable x and the
functions get() and set() are binded together which is nothing but
encapsulation.
Low complexity
Better understanding
class Box {
public:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
In other words :
Syntax:
ClassName ObjectName;
Both of the objects Box1 and Box2 will have their own copy of data
members.
Accessing data members and member functions : The data members and
member functions of class can be accessed using the dot(‘.’) operator with the object. For
example if the name of object is obj and you want to access the member function with the
name printName() then you will have to write obj.printName() .
The public data members are also accessed in the same way given
however the private data members are not allowed to be accessed directly by the object.
Accessing a data member depends solely on the access control of that data member.
This access control is given by Access modifiers in C++. There are three access
modifiers : public, private and protected.
1. Public mode: If we derive a sub class from a public base class. Then
the public member of the base class will become public in the derived
class and protected members of the base class will become protected in
derived class. Private members of the base class will never get inherited
in sub class.
2. Protected mode: If we derive a sub class from a Protected base class.
Then both public member and protected members of the base class will
become protected in derived class. Private members of the base class
will never get inherited in sub class.
3. Private mode: If we derive a sub class from a Private base class. Then
both public member and protected members of the base class will
become Private in derived class. Private members of the base class will
never get inherited in sub class.
// C++ program to demonstrate accessing of data members
#include <iostream.h>
class Geeks
public:
string geekname;
void printname()
{
};
int main() {
Geeks obj1;
obj1.geekname = "Abhi";
obj1.printname();
return 0;
Run on IDE
Output:
#include <iostream.h>
using namespace std;
class Geeks
public:
string geekname;
int id;
void printname();
void printid()
{
}
};
void Geeks::printname()
int main() {
Geeks obj1;
obj1.geekname = "xyz";
obj1.id=15;
obj1.printname();
obj1.printid();
return 0;
Run on IDE
Output:
Geek id is: 15
Note that all the member functions defined inside the class definition are by default inline,
but you can also make any non-class function inline by using keyword inline with them.
Inline functions are actual functions, which are copied everywhere during compilation, like
pre-processor macro, so the overhead of function calling is reduced.
class Test
{
private:
int data1;
float data2;
public:
void insertIntegerData(int d)
{
data1 = d;
cout << "Number: " << data1;
}
float insertFloatData()
{
cout << "\nEnter data: ";
cin >> data2;
return data2;
}
};
int main()
{
Test o1, o2;
float secondDataOfObject2;
o1.insertIntegerData(12);
secondDataOfObject2 = o2.insertFloatData();
Output
Number: 12
o1.insertIntegerData(12);
secondDataOfObject2 = o2.insertFloatData();
#include <iostream>
class stud
{
public:
char name[30],clas[10];
int rol,age;
void enter()
void display()
cout<<"\n Age\tName\tR.No.\tClass";
cout<<"\n"<<age<<"\t"<<name<<"\t"<<rol<<"\t"<<clas;
};
int main()
class stud s;
s.enter();
s.display();
Syntax of Function
return-type function-name (parameters)
// function-body
return-type : suggests what the function will return. It can be int, char,
some pointer or even a class object. There can be functions which does not
return anything, they are mentioned with void.
Function Name : is the name of the function, using the function name it is
called.
Parameters : are variables to hold values of arguments passed while
function is called. A function may or may not contain parameter list.
void sum(int x, int y)
{
int z;
z = x + y;
cout << z;
}
int main()
{
int a = 10;
int b = 20;
}
Function body : is he part where the code statements are written.
int main()
int a = 10;
int b = 20;
cout << c;
return (X + y);
Here, initially the function is declared, without body. Then inside main()
function it is called, as the function returns summation of two values, hence z
is there to store the value of sum. Then, at last, function is defined, where the
body of function is mentioned. We can also, declare & define the function
together, but then it should be done before it is called.
Calling a Function
Functions are called by their names. If the function is without argument, it can
be called directly using its name. But for functions with arguments, we have two
ways to call them,
1. Call by Value
2. Call by Reference
Call by Value
In this calling technique we pass the values of arguments which are stored or
copied into the formal parameters of functions. Hence, the original values are
unchanged only the parameters inside function changes.
void calc(int x);
int main()
int x = 10;
calc(x);
printf("%d", x);
void calc(int x)
x = x + 10 ;
Output : 10
In this case the actual variable x is not changed, because we pass argument by
value, hence a copy of x is passed, which is changed, and that copied value is
destroyed as the function ends(goes out of scope). So the variable x inside
main() still has a value 10.
But we can change this program to modify the original x, by making the
function calc() return a value, and storing that value in x.
int calc(int x);
int main()
{
int x = 10;
x = calc(x);
printf("%d", x);
int calc(int x)
x = x + 10 ;
return x;
Output : 20
Call by Reference
In this we pass the address of the variable as arguments. In this case the
formal parameter can be taken as a reference or a pointer, in both the case
they will change the values of the original variable.
void calc(int *p);
int main()
int x = 10;
printf("%d", x);
*p = *p + 10;
Output : 20
Constructors
Constructors are special type of member functions that initializes
an object automatically when it is created.
OR
Constructors are special class functions which performs initialization of every
object. The Compiler calls the Constructor whenever an object is created.
Constructors iitialize values to object members after storage is allocated to the
object.
class A
int x;
public:
A(); //Constructor
};
While defining a contructor you must remeber that the name of constructor will
be same as the name of the class, and contructors never have return type.
Constructors can be defined either inside the class definition or outside class
definition using class name and scope resolution :: operator.
Syntax
class class-name {
Access Specifier :
Member - Variables
Member - Functions
public:
class-name() {
// Constructor code
}
class A
int i;
public:
i=1;
Example Program
/* Example Program For Simple Example Program Of Constructor In C++ */
#include<iostream>
#include<conio.h>
class Example {
// Variable Declaration
int a, b;
public:
//Constructor
Example() {
// Assign Values In Constructor
a = 10;
b = 20;
cout << "Im Constructor\n";
}
void Display() {
cout << "Values :" << a << "\t" << b;
}
};
int main() {
Example Object;
// Constructor invoked.
Object.Display();
Types of Constructors
Constructors are of three types :
1. Default Constructor
2. Parametrized Constructor
3. Copy COnstructor
Default Constructor
Default constructor is the constructor which doesn't take any argument. It has
no parameter.
Syntax :
class_name ()
{ Constructor Definition }
Example :
class Cube
int side;
public:
Cube()
side=10;
}
};
int main()
Cube c;
Output : 10
In this case, as soon as the object is created the constructor is called which
initializes its data members.
A default constructor is so important for initialization of object members, that
even if we do not define a constructor explicitly, the compiler will provide a
default constructor implicitly.
class Cube
public:
int side;
};
int main()
Cube c;
Output : 0
In this case, default constructor provided by the compiler will be called which
will initialize the object data members to default value, that will be 0 in this
case.
Parameterized Constructor
These are the constructors with parameter. Using this Constructor you can
provide different values to data members of different objects, by passing the
appropriate values as argument.
In other words
A default constructor does not have any parameter, but if you need, a
constructor can have parameters. This helps you to assign initial value to an
object at the time of its creation as shown in the following example:
Access Specifier :
Member - Variables
Member - Functions
public:
class-name(variables) {
// Constructor code
}
class Example {
// Variable Declaration
int a, b;
public:
//Constructor
Example(int x, int y) {
// Assign Values In Constructor
a = x;
b = y;
cout << "Im Constructor\n";
}
void Display() {
cout << "Values :" << a << "\t" << b;
}
};
int main() {
Example Object(10, 20);
// Constructor invoked.
Object.Display();
Sample Output
Im Constructor
Values :10 20
Example :
class Cube
public:
int side;
Cube(int x)
side=x;
}
};
int main()
Cube c1(10);
Cube c2(20);
Cube c3(30);
OUTPUT : 10 20 30
Copy Constructor
These are special type of Constructors which takes an object as argument, and
is used to copy values of data members of one object into other object.
In other words:
In the above code, for the second statement, the compiler will copy the instance
S1 to S2 member by member. If you have not defined a copy constructor, the
compiler automatically, creates it and it is public.
Syntax
class class-name {
Access Specifier :
Member - Variables
Member - Functions
public:
class-name(variable) {
// Constructor code
}
Example Program
/* Example Program For Simple Example Program Of Copy Constructor Overloading In C++
#include<iostream>
#include<conio.h>
class Example {
// Variable Declaration
int a, b;
public:
Example(int x, int y) {
// Assign Values In Constructor
a = x;
b = y;
cout << "\nIm Constructor";
}
void Display() {
cout << "\nValues :" << a << "\t" << b;
}
};
int main() {
Example Object(10, 20);
//Copy Constructor
Example Object2 = Object;
// Constructor invoked.
Object.Display();
Object2.Display();
Sample Output
Im Constructor
Values :10 20
Values :10 20
Constructor Overloading
Just like other member functions, constructors can also be overloaded. Infact
when you have both default and parameterized constructors defined in your
class you are having Overloaded Constructors, one with no parameter and other
with parameter.
You can have any number of Constructors in a class that differ in parameter list.
class Student
int rollno;
string name;
public:
Student(int x)
rollno=x;
name="None";
rollno=x ;
name=str ;
};
int main()
Student A(10);
Student B(11,"Ram");
#include<iostream>
#include<conio.h>
class Example {
// Variable Declaration
int a, b;
public:
Example() {
// Assign Values In Constructor
a = 50;
b = 100;
cout << "\nIm Constructor";
}
Example(int x, int y) {
// Assign Values In Constructor
a = x;
b = y;
cout << "\nIm Constructor";
}
void Display() {
cout << "\nValues :" << a << "\t" << b;
}
};
int main() {
Example Object(10, 20);
Example Object2;
// Constructor invoked.
Object.Display();
Object2.Display();
// Wait For Output Screen
getch();
return 0;
}
Sample Output
Im Constructor
Im Constructor
Values :10 20
Values :50 100
Instead, you can define a constructor that initialises age to 0. Then, all you have to do is
create a Person object and the constructor will automatically initialise the age.
Also, if you want to execute some code immediately after an object is created, you can
place the code inside the body of the constructor.
Special Characteristics of Constructors
Destructors
Destructor is a special class function which destroys the object as soon as the
scope of object ends. The destructor is called automatically by the compiler
when the object goes out of scope.
A destructor will have exact same name as the class prefixed with a tilde
(~) and it can neither return a value nor can it take any parameters.
Destructor can be very useful for releasing resources before coming out of
the program like closing files, releasing memories etc.
The syntax for destructor is same as that for the constructor, the class name is
used for the name of destructor, with a tilde ~ sign as prefix to it.
class A
public:
~A();
};
Example
#include<iostream>
using namespace std;
class Marks
{
public:
int maths;
int science;
//constructor
Marks() {
cout << "Inside Constructor"<<endl;
cout << "C++ Object created"<<endl;
}
//Destructor
~Marks() {
cout << "Inside Destructor"<<endl;
cout << "C++ Object destructed"<<endl;
}
};
int main( )
{
Marks m1;
Marks m2;
return 0;
}
Output
Inside Constructor
C++ Object created
Inside Constructor
C++ Object created
Inside Destructor
C++ Object destructed
Inside Destructor
C++ Object destructed
Fundamentally, there are 2 styles when writing methods of object instantiations with class.
1. The first style assigns a variable with the instantiation of the object itself (as seen in type A).
2. The second, goes for a more versatile approach by using a variable to store the address of the
created object (type B).
type A:
But if the argument/s are not passed while invoking a function then, the default
values are used.
#include <iostream>
using namespace std;
void display(char = '*', int = 1);
int main()
{
cout << "No argument passed:\n";
display();
return 0;
}
Output
No argument passed:
*
First argument passed:
$$$$$
In the above program, you can see the default value assigned to the
arguments void display(char = '*', int = 1); .
Then, only the first argument is passed using the function second time. In this case,
function does not use first default value passed. It uses the actual parameter
passed as the first argument c = # and takes default value n = 1 as its second
argument.
When display() is invoked for the third time passing both arguments, default
arguments are not used. So, the value of c = $ and n = 5.
The above function will not compile. You cannot miss a default argument in
between two arguments.
In this case, c should also be assigned a default value.
2. void add(int a, int b = 3, int c, int d);
The above function will not compile as well. You must provide default values for
each argument after b.
In this case, c and d should also be assigned default values.
If you want a single default argument, make sure the argument is the last one. void
add(int a, int b, int c, int d = 4);
3. No matter how you use default arguments, a function should always be written so
that it serves only one purpose.
If your function does more than one thing or the logic seems too complicated, you
can use Function overloading to separate the logic better.
C++Programming/Compiler/Linker/Libraries/
Garbage Collection
Garbage collection is a form of automatic memory management. The garbage collector or collector
attempts to reclaim garbage, or memory used by objects that will never be accessed or mutated
again by the application.
Tracing garbage collectors require some implicit runtime overhead that may be beyond the control of
the programmer, and can sometimes lead to performance problems. For example, commonly used
Stop-The-World garbage collectors, which pause program execution at arbitrary times, may make
garbage collecting languages inappropriate for some embedded systems, high-performance server
software, and applications with real-time needs.
A more fundamental issue is that garbage collectors violate locality of reference, since they
deliberately go out of their way to find bits of memory that haven't been accessed recently. The
performance of modern computer architectures is increasingly tied to caching, which depends on the
assumption of locality of reference for its effectiveness. Some garbage collection methods result in
better locality of reference than others. Generational garbage collection is relatively cache-friendly,
and copying collectors automatically defragment memory helping to keep related data together.
Nonetheless, poorly timed garbage collection cycles could have a severe performance impact on
some computations, and for this reason many runtime systems provide mechanisms that allow the
program to temporarily suspend, delay or activate garbage collection cycles.
Despite these issues, for many practical purposes, allocation/deallocation-intensive algorithms
implemented in modern garbage collected languages can actually be faster than their equivalents
using explicit memory management (at least without heroic optimizations by an expert programmer).
A major reason for this is that the garbage collector allows the runtime system to amortize allocation
and deallocation operations in a potentially advantageous fashion. For example, consider the
following program in C++:
#include <iostream>
class A {
int x;
public:
A() { x = 0; ++x; }
};
int main() {
for (int i = 0; i < 1000000000; ++i) {
A *a = new A();
delete a;
}
std::cout << "DING!" << std::endl;
}
One of more widely used libraries that provides this function is Hans Boehm's conservative GC. As
we have seen earlier C++ also supports a powerful idiom called RAII (resource acquisition is
initialization) that can be used to safely and automatically manage resources including memory.
The stack − All variables declared inside the function will take up memory from
the stack.
The heap − This is unused memory of the program and can be used to allocate
the memory dynamically when program runs.
Many times, you are not aware in advance how much memory you will need
to store particular information in a defined variable and the size of required
memory can be determined at run time.
You can allocate memory at run time within the heap for the variable of a
given type using a special operator in C++ which returns the address of the
space allocated. This operator is called new operator.
If you are not in need of dynamically allocated memory anymore, you can
use delete operator, which de-allocates memory that was previously
allocated by new operator.
new data-type;
The memory may not have been allocated successfully, if the free store had
been used up. So it is good practice to check if new operator is returning
NULL pointer and take appropriate action as below −
At any point, when you feel a variable that has been dynamically allocated
is not anymore required, you can free up the memory that it occupies in the
free store with the ‘delete’ operator as follows −
Let us put above concepts and form the following example to show how
‘new’ and ‘delete’ work −
#include <iostream>
using namespace std;
int main () {
double* pvalue = NULL; // Pointer initialized with null
pvalue = new double; // Request memory for the variable
return 0;
}
If we compile and run above code, this would produce the following result −
To remove the array that we have just created the statement would look
like this −
Following the similar generic syntax of new operator, you can allocate for a
multi-dimensional array as follows −
However, the syntax to release the memory for multi-dimensional array will
still remain same as above −
delete [] pvalue; // Delete array pointed to by pvalue
#include <iostream>
using namespace std;
class Box {
public:
Box() {
cout << "Constructor called!" <<endl;
}
~Box() {
cout << "Destructor called!" <<endl;
}
};
int main() {
Box* myBoxArray = new Box[4];
delete [] myBoxArray; // Delete array
return 0;
}
If you were to allocate an array of four Box objects, the Simple constructor
would be called four times and similarly while deleting these objects,
destructor will also be called same number of times.
If we compile and run above code, this would produce the following result −
Constructor called!
Constructor called!
Constructor called!
Constructor called!
Destructor called!
Destructor called!
Destructor called!
Destructor called!
Abstract Class
Abstract Class is a class which contains atleast one Pure Virtual function in it. Abstract
classes are used to provide an Interface for its sub classes. Classes inheriting an Abstract
Class must provide definition to the pure virtual function, otherwise they will also become
abstract class.
1. Abstract class cannot be instantiated, but pointers and refrences of Abstract class type
can be created.
2. Abstract class can have normal functions and variables along with a pure virtual
function.
3. Abstract classes are mainly used for Upcasting, so that its derived classes can use its
interface.
4. Classes inheriting an Abstract Class must implement all pure virtual functions, or else
they will become Abstract too.
public:
public:
void show()
};
int main()
Base *b;
Derived d;
b = &d;
b->show();
Output :
Implementation of Virtual Function in Derived class
In the above example Base class is abstract, with pure virtual show() function, hence we
cannot create object of base class.
Pure Virtual functions can be given a small definition in the Abstract class, which you
want all the derived classes to have. Still you cannot create object of Abstract class.
Also, the Pure Virtual function must be defined outside the class definition. If you will
define it inside the class definition, complier will give an error. Inline pure virtual
definition is Illegal.
public:
};
public:
void show()
};
int main()
Base *b;
Derived d;
b = &d;
b->show();
Output :
Pure Virtual definition
Metaclass
In object-oriented programming, a metaclass is a class whose instances are classes. Just as an
ordinary class defines the behavior of certain objects, a metaclass defines the behavior of certain
classes and their instances. Not all object-oriented programming languages support metaclasses.
Among those that do, the extent to which metaclasses can override any given aspect of class
behavior varies. Metaclasses can be implemented by having classes be first-class citizen, in which
case a metaclass is simply an object that constructs classes. Each language has its own metaobject
protocol, a set of rules that govern how objects, classes, and metaclasses interact. [1]