Unit 4
What are Pointers?
In C++, a pointer refers to a variable that holds the address of another variable. Like
regular variables, pointers have a data type. For example, a pointer of type integer
can hold the address of a variable of type integer. A pointer of character type can
hold the address of a variable of character type.
You should see a pointer as a symbolic representation of a memory address. With
pointers, programs can simulate call-by-reference. They can also create and
manipulate dynamic data structures. In C++, a pointer variable refers to a variable
pointing to a specific address in a memory pointed by another variable.
Pointer Declaration Syntax
The declaration of C++ takes the following syntax:
datatype *variable_name;
The datatype is the base type of the pointer which must be a valid C+
+ data type.
The variable_name is should be the name of the pointer variable.
Asterisk used above for pointer declaration is similar to asterisk used
to perform multiplication operation. It is the asterisk that marks the
variable as a pointer.
Here is an example of valid pointer declarations in C++:
int *x; // a pointer to integer
double *x; // a pointer to double
float *x; // a pointer to float
char *ch // a pointer to a character
Reference operator (&) and Deference operator
(*)
The reference operator (&) returns the variable’s address.
The dereference operator (*) helps us get the value that has been stored in
a memory address.
For example:
If we have a variable given the name num, stored in the address 0x234 and
storing the value 28.
The reference operator (&) will return 0x234.
The dereference operator (*) will return 5.
Example 1:
#include <iostream>
using namespace std;
int main() {
int x = 27;
int *ip;
ip = &x;
cout << "Value of x is : ";
cout << x << endl;
cout << "Value of ip is : ";
cout << ip<< endl;
cout << "Value of *ip is : ";
cout << *ip << endl;
return 0;
}
Output:
How this works:
C++ Pointer Arithmetic
As you understood pointer is an address which is a numeric value; therefore, you
can perform arithmetic operations on a pointer just as you can a numeric value.
There are four arithmetic operators that can be used on pointers: ++, --, +, and -
To understand pointer arithmetic, let us consider that ptr is an integer pointer which
points to the address 1000. Assuming 32-bit integers, let us perform the following
arithmetic operation on the pointer −
ptr++
the ptr will point to the location 1004 because each time ptr is incremented, it will
point to the next integer. This operation will move the pointer to next memory
location without impacting actual value at the memory location. If ptr points to a
character whose address is 1000, then above operation will point to the location
1001 because next character will be available at 1001.
Incrementing a Pointer
We prefer using a pointer in our program instead of an array because the variable
pointer can be incremented, unlike the array name which cannot be incremented
because it is a constant pointer. The following program increments the variable
pointer to access each succeeding element of the array −
Live Demo
#include <iostream>
using namespace std;
const int MAX = 3;
int main () {
int var[MAX] = {10, 100, 200};
int *ptr;
// let us have array address in pointer.
ptr = var;
for (int i = 0; i < MAX; i++) {
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;
cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;
// point to the next location
ptr++;
}
return 0;
}
When the above code is compiled and executed, it produces result something as
follows −
Address of var[0] = 0xbfa088b0
Value of var[0] = 10
Address of var[1] = 0xbfa088b4
Value of var[1] = 100
Address of var[2] = 0xbfa088b8
Value of var[2] = 200
Decrementing a Pointer
The same considerations apply to decrementing a pointer, which decreases its
value by the number of bytes of its data type as shown below −
Live Demo
#include <iostream>
using namespace std;
const int MAX = 3;
int main () {
int var[MAX] = {10, 100, 200};
int *ptr;
// let us have address of the last element in pointer.
ptr = &var[MAX-1];
for (int i = MAX; i > 0; i--) {
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;
cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;
// point to the previous location
ptr--;
}
return 0;
}
When the above code is compiled and executed, it produces result something as
follows −
Address of var[3] = 0xbfdb70f8
Value of var[3] = 200
Address of var[2] = 0xbfdb70f4
Value of var[2] = 100
Address of var[1] = 0xbfdb70f0
Value of var[1] = 10
Pointer Comparisons
Pointers may be compared by using relational operators, such as ==, <, and >. If p1
and p2 point to variables that are related to each other, such as elements of the
same array, then p1 and p2 can be meaningfully compared.
The following program modifies the previous example one by incrementing the
variable pointer so long as the address to which it points is either less than or equal
to the address of the last element of the array, which is &var[MAX - 1] −
Live Demo
#include <iostream>
using namespace std;
const int MAX = 3;
int main () {
int var[MAX] = {10, 100, 200};
int *ptr;
// let us have address of the first element in pointer.
ptr = var;
int i = 0;
while ( ptr <= &var[MAX - 1] ) {
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;
cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;
// point to the previous location
ptr++;
i++;
}
return 0;
}
When the above code is compiled and executed, it produces result something as
follows −
Address of var[0] = 0xbfce42d0
Value of var[0] = 10
Address of var[1] = 0xbfce42d4
Value of var[1] = 100
Address of var[2] = 0xbfce42d8
Value of var[2] = 200
Using Pointers with Objects
A pointer to a C++ class is done exactly the same way as a pointer to a structure and
to access members of a pointer to a class you use the member access operator ->
operator, just as you do with pointers to structures. Also as with all pointers, you
must initialize the pointer before using it.
For accessing normal data members we use the dot . operator with
object and -> qith pointer to object. But when we have a pointer to
data member, we have to dereference that pointer to get what its
pointing to, hence it becomes,
Object.*pointerToMember
Copy
and with pointer to object, it can be accessed by writing,
ObjectPointer->*pointerToMember
Lets take an example, to understand the complete concept.
class Data
{
public:
int a;
void print()
{
cout << "a is "<< a;
}
};
int main()
{
Data d, *dp;
dp = &d; // pointer to object
int Data::*ptr=&Data::a; // pointer to data member 'a'
d.*ptr=10;
d.print();
dp->*ptr=20;
dp->print();
}
Output:
a is 10
a is 20
C++ this Pointer
In C++ programming, this is a keyword that refers to the current instance of the
class. There can be 3 main usage of this keyword in C++.
o It can be used to pass current object as a parameter to another method.
o It can be used to refer current class instance variable.
o It can be used to declare indexers.
C++ this Pointer Example
Let's see the example of this keyword in C++ that refers to the fields of current class.
1. #include <iostream>
2. class Employee {
3. public:
4. int id; //data member (also instance variable)
5. string name; //data member(also instance variable)
6. float salary;
7. Employee(int id, string name, float salary)
8. {
9. this->id = id;
10. this->name = name;
11. this->salary = salary;
12. }
13. void display()
14. {
15. cout<<id<<" "<<name<<" "<<salary<<endl;
16. }
17. };
18. int main() {
19. Employee e1 =Employee(101, "Sonoo", 890000); //creating an object of Em
ployee
20. Employee e2=Employee(102, "Nakul", 59000); //creating an object of Emplo
yee
21. e1.display();
22. e2.display();
23. return 0;
24. }
Output:
101 Sonoo 890000
102 Nakul 59000
Pointer to Derived Class
In C++, we can declare a pointer points to the base class as well as derive class.
Consider below example to understand pointer to derived class
#include<iostream.h>
class base
{
public:
int n1;
void show()
{
cout<<”\nn1 = “<<n1;
}
};
class derive : public base
{
public:
int n2;
void show()
{
cout<<”\nn1 = “<<n1;
cout<<”\nn2 = “<<n2;
}
};
int main()
{
base b;
base *bptr; //base pointer
cout<<”Pointer of base class points to it”;
bptr=&b; //address of base class
bptr->n1=44; //access base class via base pointer
bptr->show();
derive d;
cout<<”\n”;
bptr=&d; //address of derive class
bptr->n1=66; //access derive class via base pointer
bptr->show();
return 0;
}
Output
Pointer of base class points to it
n1 = 44
Pointer of base class points to derive class
n1=66
Here the show() method is the overridden method, bptr execute show() method of ‘base’ class
twice and display its content. Even though bptr first points to ‘base’ and second time points to
‘derive’ ,both the time bptr->show() executes the ‘base’ method show()
C++ Polymorphism
The term "Polymorphism" is the combination of "poly" + "morphs" which means many
forms. It is a greek word. In object-oriented programming, we use 3 main concepts:
inheritance, encapsulation, and polymorphism.
Real Life Example Of Polymorphism
Let's consider a real-life example of polymorphism. A lady behaves like a teacher in a
classroom, mother or daughter in a home and customer in a market. Here, a single person is
behaving differently according to the situations.
There are two types of polymorphism in C++:
o Compile time polymorphism: The overloaded functions are invoked by matching
the type and number of arguments. This information is available at the compile time
and, therefore, compiler selects the appropriate function at the compile time. It is
achieved by function overloading and operator overloading which is also known as
static binding or early binding. Now, let's consider the case where function name and
prototype is same.
1. class A // base class declaration.
2. {
3. int a;
4. public:
5. void display()
6. {
7. cout<< "Class A ";
8. }
9. };
10. class B : public A // derived class declaration.
11. {
12. int b;
13. public:
14. void display()
15. {
16. cout<<"Class B";
17. }
18. };
In the above case, the prototype of display() function is the same in both the base
and derived class. Therefore, the static binding cannot be applied. It would be great
if the appropriate function is selected at the run time. This is known as run time
polymorphism.
o Run time polymorphism: Run time polymorphism is achieved when the
object's method is invoked at the run time instead of compile time. It is
achieved by method overriding which is also known as dynamic binding or
late binding.
Differences b/w compile time and run time
polymorphism.
Compile time polymorphism Run time polymorphism
The function to be invoked is known at the The function to be invoked is known
compile time. at the run time.
It is also known as overloading, early It is also known as overriding,
binding and static binding. Dynamic binding and late binding.
Overloading is a compile time Overriding is a run time
polymorphism where more than one polymorphism where more than one
method is having the same name but with method is having the same name,
the different number of parameters or the number of parameters and the type
type of the parameters. of the parameters.
It is achieved by function overloading and It is achieved by virtual functions and
operator overloading. pointers.
It provides fast execution as it is known at It provides slow execution as it is
the compile time. known at the run time.
It is less flexible as mainly all the things It is more flexible as all the things
execute at the compile time. execute at the run time.
C++ Runtime Polymorphism Example
Let's see a simple example of run time polymorphism in C++.
// an example without the virtual keyword.
1. #include <iostream>
2. using namespace std;
3. class Animal {
4. public:
5. void eat(){
6. cout<<"Eating...";
7. }
8. };
9. class Dog: public Animal
10. {
11. public:
12. void eat()
13. { cout<<"Eating bread...";
14. }
15. };
16. int main(void) {
17. Dog d = Dog();
18. d.eat();
19. return 0;
20. }
1. Compile Time Polymorphism
In compile-time polymorphism, a function is called at the time of program compilation.
We call this type of polymorphism as early binding or Static binding.
Function overloading and operator overloading is the type of Compile time
polymorphism.
I. Function Overloading
Function overloading means one function can perform many tasks. In C++, a single
function is used to perform many tasks with the same name and different types of
arguments. In the function overloading function will call at the time of program
compilation. It is an example of compile-time polymorphism.
In the below example, A function ADD() is used to perform two tasks. The two asks
would be to add two integer values and add two strings (concatenate).
Readability of the program increases by function overloading. It is achieved by using the
same name for the same action.
Source Code:
1 #include <iostream>
2 using namespace std;
class Addition {
3
public:
4
5 int ADD(int X,int Y) // Function with parameter
6 {
7 return X+Y; // this function is performing addition of two Integer val
8 }
9 int ADD() { // Function with same name but without parameter
string a= "HELLO";
10
string b="SAM"; // in this function concatenation is performed
11
string c= a+b;
12
cout<<c<<endl;
13
14
}
15
};
16 int main(void) {
17 Addition obj; // Object is created
18 cout<<obj.ADD(128, 15)<<endl; //first method is called
19 obj.ADD(); // second method is called
return 0;
20
}
21
22
Output
143
HELLOSAM
In the above example, we use function ADD() to perform many tasks which is a property
of polymorphism in C++.
II. Operator Overloading
Operator overloading means defining additional tasks to operators without changing its
actual meaning. We do this by using operator function.
The purpose of operator overloading is to provide a special meaning to the user-defined
data types.
The advantage of Operators overloading is to perform different operations on the same
operand.
Source Code
1 #include <iostream>
2 using namespace std;
class A
3
{
4
5
string x;
6
public:
7
A(){}
8 A(string i)
9 {
10 x=i;
11 }
12 void operator+(A);
void display();
13
};
14
15
void A:: operator+(A a)
16
{
17
18
string m = x+a.x;
19
cout<<"The result of the addition of two objects is : "<<m;
20
21
22
}
23 int main()
24 {
25 A a1("Welcome");
26 A a2("back");
27 a1+a2;
return 0;
28
}
29
30
Output
The result of the addition of two objects is: Welcomeback
2. Runtime Polymorphism
In a Runtime polymorphism, functions are called at the time the program execution.
Hence, it is known as late binding or dynamic binding.
Function overriding is a part of runtime polymorphism. In function overriding, more than
one method has the same name with different types of the parameter list.
It is achieved by using virtual functions and pointers. It provides slow execution as it is
known at the run time. Thus, It is more flexible as all the things executed at the run time.
I. Function overriding
In function overriding, we give the new definition to base class function in the derived
class. At that time, we can say the base function has been overridden. It can be only
possible in the ‘derived class’. In function overriding, we have two definitions of the
same function, one in the superclass and one in the derived class. The decision about
which function definition requires calling happens at runtime. That is the reason we call
it ‘Runtime polymorphism’.
Source code
1
2 #include <iostream>
3 using namespace std;
4 class Animal {
public:
5
void function(){
6
cout<<"Eating..."<<endl;
7
}
8
};
9 class Man: public Animal
10 {
11 public:
12 void function()
13 {
cout<<"Walking ..."<<endl;
14
}
15
};
16
int main(void) {
17
Animal A =Animal();
18
A.function(); //parent class object
19 Man m = Man();
20 m.function(); // child class object
21
22 return 0;
23 }
24
Output
Eating …..
Walking……
II. Virtual Function
A virtual function is declared by keyword virtual. The return type of virtual function may
be int, float, void.
A virtual function is a member function in the base class. We can redefine it in a derived
class. It is part of run time polymorphism. The declaration of the virtual function must be
in the base class by using the keyword virtual. A virtual function is not static.
The virtual function helps to tell the compiler to perform dynamic binding or late binding
on the function.
If it is necessary to use a single pointer to refer to all the different classes’ objects. This is
because we will have to create a pointer to the base class that refers to all the derived
objects.
But, when the base class pointer contains the derived class address, the object always
executes the base class function. For resolving this problem, we use the virtual function.
When we declare a virtual function, the compiler determines which function to invoke at
runtime.
Let’s see the below example for understanding how the program execution happens
without virtual function and with virtual function.
Source code
1 //without virtual Function
2
4
#include <iostream>
5
using namespace std;
6
class Add
7
{
8
int x=5, y=20;
9
public:
10 void display() //overridden function
11 {
12 cout << "Value of x is : " << x+y<<endl;
13 }
14 };
class Substract: public Add
15
{
16
int y = 10,z=30;
17
public:
18
void display() //overridden function
19 {
20 cout << "Value of y is : " <<y-z<<endl;
21 }
22 };
23 int main()
{
24
Add *m; //base class pointer .it can only access the base class memb
25
Substract s; // making object of derived class
26
m = &s;
27
m->display(); // Accessing the function by using base class pointer
28 return 0;
29 }
30
Output
Value of x is: 25
Virtual Function used to invoke the derived class in a program.
Source Code
1 #include<iostream>
2 using namespace std;
3
class Add
4
{
5
public:
6
virtual void print ()
7
{ int a=20, b=30;
8 cout<< " base class Action is:"<<a+b <<endl;
9 }
10
11 void show ()
12 { cout<< "show base class" <<endl; }
13 };
14
class Sub: public Add
15
{
16
public:
17
void print () //print () is already virtual function in derived class, we could
18
{ int x=20,y=10;
19
20
cout<< " derived class Action:"<<x-y <<endl; }
21
22 void show ()
23 { cout<< "show derived class" <<endl; }
24
25
};
26
27
//main function
28
int main()
29 {
30 Add *aptr;
31 Sub s;
32 aptr = &s;
33
34 //virtual function, binded at runtime (Runtime polymorphism)
aptr->print();
35
36
// Non-virtual function, binded at compile time
37
aptr->show();
38
39
return 0;
40
}
41
42
Output
derived class Action:10
Pure virtual Function
When the function has no definition, we call such functions as “Do-nothing function or
Pure virtual function”. The declaration of this function happens in the base class with no
definition.
Source Code
1 #include <iostream>
2 using namespace std;
3 class Animal
4 {
5 public:
6 virtual void show() = 0; //Pure virtual function declaration.
7 };
8 class Man: public Animal
9 {
10 public:
11 void show()
12 {
13 cout << "Man is the part of animal husbandry " << endl;
14 }
15 };
16 int main()
17 {
18 Animal *aptr; //Base class pointer
19 //Animal a;
20 Man m; //derived class object creation.
21 aptr = &m;
22 aptr->show();
23 return 0;
24 }
Unary Operator Overloading:
Q. Write a C++ program to overload unary operators that is increment and decrement.
Answer:
Operator overloading is a type of polymorphism in which an operator is overloaded to give user
defined meaning to it. It is used to perform operation on user-defined data type.
Following program is overloading unary operators: increment (++) and decrement (--).
#include<iostream>
using namespace std;
class IncreDecre
{
int a, b;
public:
void accept()
{
cout<<"\n Enter Two Numbers : \n";
cout<<" ";
cin>>a;
cout<<" ";
cin>>b;
}
void operator--() //Overload Unary Decrement
{
a--;
b--;
}
void operator++() //Overload Unary Increment
{
a++;
b++;
}
void display()
{
cout<<"\n A : "<<a;
cout<<"\n B : "<<b;
}
};
int main()
{
IncreDecre id;
id.accept();
--id;
cout<<"\n After Decrementing : ";
id.display();
++id;
++id;
cout<<"\n\n After Incrementing : ";
id.display();
return 0;
}
Output:
Binary Operator Overloading
As the name suggests, those operators which operate on two operands or data are called binary
operators.
Here is an example to show how binary operators are overloaded in C++.
Example: C++ program to illustrate binary operator overloading
#include<iostream>
using namespace std;
class complex
{
private:
int real,imag;
public:
void getvalue()
{
cout<<"Enter the value of real number:";
cin>>real;
cout<<"Enter the value of imaginary number:";
cin>>imag;
}
complex operator+(complex obj)
{
complex temp;
temp.real=real+obj.real;
temp.imag=imag+obj.imag;
return(temp);
}
complex operator-(complex obj)
{
complex temp;
temp.real=real-obj.real;
temp.imag=imag-obj.imag;
return(temp);
}
void display()
{
cout<<real<<"+"<<"("<<imag<<")"<<"i"<<"\n";
}
};
int main()
{
complex c1,c2,c3,c4;
c1.getvalue();
c2.getvalue();
c3 = c1+c2;
c4 = c1-c2;
cout<<"Result is:\n";
c3.display();
c4.display();
return 0;
}