C++ - Unit II
C++ - Unit II
C++ - Unit II
Data Structures
Unit II
Classes and Objects
CLASS:
• Class is a group of objects that share common properties and relationships . A
class is a new data type that contains member variables and member functions that
operates on the variables.
• A class is defined with the keyword class.
• It allows the data to be hidden, if necessary from external use.
• When we defining a class, we are creating a new abstract data type that can be
treated like any other built in data type.
Generally a class specification has two parts:-
a) Class declaration - describes the type and scope of its members
b) Class function definition - describes how the class functions are implemented
Classes and Objects …Cont’d
Syntax:-
class class-name
{
private: The data hiding is the key feature of oops.
variable declarations; The use of keywords private is optional by
function declaration ; default, the members of a class are private.
The variables declared inside the class are
public: known as data members and the functions
variable declarations;
are known as members functions.
function declaration;
}; Only the member functions can have
access to the private data members and
• The members that have been declared as private functions.
private can be accessed only from with in However, the public members can be
the class. accessed from the outside the class.
The binding of data and functions together
• On the other hand , public members can be into a single class type variable is referred to
accessed from outside the class also. as encapsulation.
Classes and Objects …Cont’d
Syntax:-
class item
{
int member; Data Members
float cost;
public:
void getldata (int a ,float b); Member Functions
void putdata (void);
}
The class item contains two data members and two Member Functions, the data members are
private by default while both the functions are public by declaration.
The function getdata() can be used to assign values to the member variables member and cost,
and putdata() for displaying their values . These functions provide the only access to the data
members from outside the class.
Classes and Objects …Cont’d
CREATING OBJECTS:
When a class is defined, only the specification for the object is defined; no memory or storage is
allocated. To use the data and access functions defined in the class, you need to create objects. Syntax
: ClassName ObjectName;
Example: item x;
creates a variables x of type item. In C++, the class variables are known as objects. Therefore x is called an
object of type item. Item x, y ,z also possible.
class item
{
-----------
-----------
-----------
}x ,y ,z; //would create the objects x ,y ,z of type item.
To define a member function outside the class definition we have to use the scope resolution
operator :: along with class name and function name.
An important difference between a member function and a normal function is that a member
function incorporates a membership. Identify label in the header. The ‘label’ tells the compiler which class
the function belongs to.
Defining and Accessing Member Functions in Classes // Definition of printname using scope resolution operator ::
void Name::printname()
{
In the below Example program cout << “My name is: " << Myname;
Function printid() is defined within the class, Name. }
Function printname is declared within the class and defined int main() {
outside the class using :: (Scope resolution operator) Name obj1;
obj1.Myname = “Madhu";
// C++ program to demonstrate function declaration outside class obj1.id=15;
#include <iostream.h> // call printname()
using namespace std; obj1.printname();
class Name cout << endl;
{ // call printid()
public: obj1.printid();
string Myname; return 0;
int id; }
// printname is not defined inside class definition
void printname(); Output:
// printid is defined inside class definition
void printid() My name is: Madhu
{ My id is: 15
cout << “My id is: " << id;
}
};
Classes and Objects …Cont’d
Sample program using class in C++ to input subject mark void main()
and prints it. {
class marks
{ clrscr();
private : marks x;
int ml,m2;
public: x.getdata();
void getdata(); x.displaydata();
void displaydata();
}; }
void marks :: getdata()
Output:
{
cout<<”enter 1st subject mark:”; enter 1st subject mark: 76
cin>>ml; enter 2nd subject mark: 56
cout<<”enter 2nd subject mark:”;
cin>>m2; 1st subject mark: 76
} 2nd subject mark: 56
void marks:: displaydata()
{
cout<<”1st subject mark:”<<ml<<endl ;
cout<<”2nd subject mark:”<<m2;
}
Classes and Objects …Cont’d
is illegal. How ever the function read() can be called by the function update ( ) to update the
value of m.
The array variable a{} declared as a private member of the class array can be used in the member
functions like any other variables. We can perform any operations on it.
Classes and Objects …Cont’d
Static variables are normally used to maintain values common to the entire class. For example a
static data member can be used as a counter that records the occurrence of all the objects.
Note that the type and scope of each static member variable must be defined outside the class
definition. This is necessary because the static data members are stored separately rather than as a
part of an object.
Classes and Objects …Cont’d
The first method is called pass-by-value. Since a copy of the object is passed to the function,
any change made to the object inside the function do not effect the object used to call the function.
The second method is called pass-by-reference . When an address of the object is passed, the
called function works directly on the actual object used in the call. This means that any changes
made to the object inside the functions will reflect in the actual object .
The pass by reference method is more efficient since it requires to pass only the address of the
object and not the entire object.
Classes and Objects …Cont’d
Use of object as Function argument int main()
#include<iostream.h> {
class time
{ time T1,T2,T3;
int hours; T1.gettime(2,45);
int minutes;
public: T2.gettime(3,30);
void gettime(int h, int m) T3.sum(T1,T2);
{
hours=h; cout<<”T1=”;
minutes=m;
T1.puttime( );
}
void puttime(void) cout<<”T2=”;
{
cout<< hours<<”hours and:”; T2.puttime( );
cout<<minutes<<”minutes:”<<end; cout<<”T3=”;
}
void sum( time ,time); T3.puttime( );
}; return(0);
void time :: sum (time t1,time t2) .
{ }
minutes=t1.minutes + t2.minutes;
hours=minutes%60;
minutes=minutes%60;
hours=hours+t 1.hours+t2.hours;
}
Classes and Objects …Cont’d
Pointer to members:
It is possible to take the address of a member of a class and assign it to a pointer. The address of a
member can be obtained by applying the operator & to a “fully qualified” class member name.
A class member pointer can be declared using the operator :: * with the class name.
Example: class A
{
private
int m;
public:
void show( );
};
We can define a pointer to the member m as follows :
int A :: * ip = & A :: m
The ip pointer created thus acts like a class member in that it must be invoked with a class object. In the
above statement. The phrase A :: * means “pointer - to - member of a class” . The phrase & A :: m means the “
Address of the m member of a class”
The pointer ip can now be used to access the member m inside the member function (or friend function).
Assume that “a” is an object of “ A” declared in a member function . We can access "m" using the pointer ip as
follows.
cout<< a . * ip; // display
cout<< a.m; // same as above
The dereferencing operator ->* is used as to access a member when we use pointers to both the object
and the member. The dereferencing operator .* is used when the object itself is used with the member pointer.
Note that * ip is used like a member name.
We can also design pointers to member functions which ,then can be invoked using the dereferencing operator
in the main as shown below.
The precedence of ( ) is higher than that of .* and ->* , so the parenthesis are necessary.
Classes and Objects …Cont’d
Dereferencing operator: int main ( )
#include<iostream.h> {
class M
{ M n;
int x; void(M::*pf) (int,int) = &M :: set-xy;
int y;
public: (n*pf)( 10,20);
void set_xy(int a,int b) cout<<”sum=: ” << sum(n) << “\n”;
{
x=a; m *op = &n; //point to object n
y=b; ( op->* pf)(30,40); // invokes set-xy
}
friend int sum(M); Cout << ”sum=” << sum(n) << “\n” ;
}; return(0);
int sum (M m) }
{ output:
int M :: * px= &M :: x; //pointer to member x
int M :: * py- & m ::y; //pointer to member y sum= 30
M * pm=&m;
sum=70
int s=m.* px + pm-> *py;
return(s);
}
Constructors and Destructors
Constructors:
A constructor is a special member function whose task is to initialize the objects of its class . It is special
because its name is the same as the class name. The constructor is invoked when ever an object of its
associated class is created. It is called constructor because it construct the values of data members of the
class.
A constructor is declared and defined as follows:
//'class with a constructor
class integer
{
int m,n:
public:
Integer(void); //constructor declared
------------
------------
};
integer :: integer(void) //constructor defined
{
m=0;
n=0;
}
When a class contains a constructor like the one defined above it is guaranteed that an object created by
the class will be initialized automatically.
Constructors…Cont’d
For example:-
Integer int1; //object int 1 created
This declaration not only creates the object int1 of type integer but also initializes its data members m and n to zero.
Types of Constructors
1. Default Constructor
2. Parameterized Constructor
3. Copy Constructor
1. Default Constructors: Default constructor is the constructor which doesn’t take any argument. It has no
parameters.
// C++ program to illustrate the concept of Constructors
#include <iostream>
using namespace std;
class construct
{
public:
int a, b;
int main()
{ Output:
// Default constructor called automatically when the object is created
construct c; a: 10
cout << "a: " << c.a << endl
<< "b: " << c.b; b: 20
return 1;
}
Note: Even if we do not define any constructor explicitly, the compiler will automatically provide a default constructor implicitly.
Constructors…Cont’d
2. Parameterized constructor:
The constructors that can take arguments are called parameterized constructors. Using parameterized constructor we
can initialize the various data elements of different objects with different values when they are created.
Example:-
class integer
{
int m, n;
public:
integer( int x, int y); //Parameterized Constructor
--------
---------
};
integer:: integer (int x, int y)
{
m=x;n=y;
}
When a constructor has been parametrized, the object declaration “integer int1;” may not work. We must pass the initial
values as arguments to the constructor function when an object is declared. This can be done in two ways.
• By calling the constructor explicitly
• By calling the constructor implicitly.
Example Declarations
integer int 1 = integer(0,100); // explicit call
integer int 1(0,100); //implicit call
Constructors…Cont’d
#include<iostream.h>
class integer
{
int m,n;
public:
integer(int,int); // constructor declared
void display(void)
{
cout<<”m=:”<<m <<“\n”;
cout<<”n=”<<n <<“\n”;
}
};
3. Copy Constructor:
A copy constructor is a member function which initializes an object using another object of the same
class. A constructor can accept a reference to its own class as a parameter as shown below. Such
constructors are called as Copy constructors.
Class A
{
-----
-----
public:
A(&A);
}:
Constructors…Cont’d
#include<iostream>
using namespace std; int main()
class Point {
{
private: Point p1(10, 15); // Normal constructor is called here
int x, y;
public: Point p2 = p1; // Copy constructor is called here
Point(int x1, int y1)
{ cout << "p1.x = " << p1.getX() << ", p1.y = " << p1.getY();
x = x1;
y = y1; cout << "\np2.x = " << p2.getX() << ", p2.y = " << p2.getY();
}
return 0;
Point(Point &p2) // Copy constructor
{ }
x = p2.x;
y = p2.y;
}
Output:
int getX()
{ p1.x = 10, p1.y = 15
return x;
}
p2.x = 10, p2.y = 15
int getY()
{
return y;
}
};
Constructors…Cont’d
Constructor Overloading:
We can have more than one constructor in a class with same name, as long as each has a
different list of arguments. This concept is known as Constructor Overloading
• Overloaded constructors essentially have the same name (name of the class) and
different number of arguments.
• A constructor is called depending upon the number and type of arguments passed.
• While creating the object, arguments must be passed to let compiler know, which
constructor needs to be called.
Constructors…Cont’d
Constructor Overloading:
#include<iostream.h> sum :: sum(int p, float q ,double r)
#include<conio.h> {
class sum
{ a=p;
private; d=q;
int a; e=r;
int b;
int c; }
float d; void main( )
double e; {
public: clrscr( );
sum ( ) Constructor (Inline)
{ sum 1;
cout<<”enter a;”; sum m=sum(20,50);
cin>>a; sum n= sum(3,3.2,4.55);
cout<<”enter b;”;
cin>>b;
getch( );
cout<<”sum= “<<a+b<<endl; }
}
sum(int a, int b); Constructor
sum(int a, float d, double c); declarations
Output:
}; enter a : 3
enter b : 8
sum :: sum(int x,int y) Definition
{ sum=11
a=x; sum=70
b=y;
} sum=10.75
Constructors…Cont’d
Dynamic constructor:
The constructors can also be used to allocate memory while creating objects . This will enable
the system to allocate the right amount of memory for each object when the objects are not of the
same size, thus resulting in the saving of memory.
Dynamic Constructor:
#include<iostream.h> int main( )
#include<string.h>
class string {
{ char * first = “Joseph” ;
char *name; string name1(first),name2(“louis”),naine3( “LaGrange”),sl,s2;
int length; sl.join(name1,name2);
public:
string ( ) //constructor 1 s2.join(s1,name3);
{ namel.display( );
length=0; name2.display( );
name= new char [length+1]; /* one extra for \0 */
} name3.display( );
string( char *s) //constructor 2 s1.display( );
{ s2.display( );
length=strlen(s); Return 0;
name=new char [length+1];
strcpy(name,s); }
}
void display(void)
{ Output
cout<<name<<endl; Joseph
} Louis
void join(string &a, string &b);
}; language
void String :: join(String &a, String &b)
{
Joseph Louis
length=a. length +b . length; Joseph Louis Language
delete name;
name=new char[length+l]; /* dynamic allocation */
strcpy(name,a.name);
strcat(name,b.name);
};
Destructors:
A destructor, as the name implies, is used to destroy the objects that have been created by a
constructor. Like a constructor, the destructor is a member function whose name is the same as the class
name but is preceded by a tilde.
For Example: The destructor for the class integer can be defined as shown below:
~ integer( ) { }
A destructor never takes any argument nor does it return any value. It will be invoked implicitly by
the compiler upon exit from the program to clean up storage that is no longer accessible. It is a good
practice to declare destructors in a program since it releases memory space for future use.
New is used to allocate memory in the Constructor, we should use Delete to free that memory.
Destructor for the matrix class is defined as follows
matrix : : ~ matrix( )
{
for(int i=0; i<11;i++)
delete p[i];
delete p;
}
Destructors…Cont’d
#include<iostream.h>
int count=0;
class alpha output:-
{ Enter Main
public: no of object created 1
alpha( )
{ no of object created 2
count ++; no of object created 3
cout<<”\n no of object created :”<< count; no of object created 4
} Enter Block 1
~alpha( )
{ no of object created 5
cout<<”\n no of object destroyed :” << count; no of object destroyed 5
count--; Enter Block 2
}
};
no of object created 5
no of object destroyed 5
int main( ) Re-Enter Main
{ no of object destroyed 4
cout<<” \n \n Enter Main \n:”;
alpha A1, A2, A3, A4; no of object created 3
{ no of object created 2
cout<<” \n Enter Block 1 :\n”; no of object created 1
alpha A5;
}
{
cout<<” \n \n Enter Block2 \n”;
alpha A6;
}
cout<<\n Re-Enter Main \n:”;
return(0);
}
Operator overloading and Type Conversions
Operator Overloading:
In C++, we can make operators to work for user defined classes. This means C++ has the ability to
provide the operators with a special meaning for a data type, this ability is known as operator
overloading.
We can overload all the C++ operators except the following:
• Class members access operator (. , .*)
• Scope resolution operator (: :)
• Size operator(sizeof)
• Condition operator (? :)
Although the semantics of an operator can be extended, we can't change its syntax, the grammatical
rules that govern its use such as the no of operands precedence and associativety. For example the
multiplication operator will enjoy higher precedence than the addition operator.
When an operator is overloaded, its original meaning is not lost. For example, the operator +, which has
been overloaded to add two vectors, can still be used to add two integers.
Syntax:
return-type class-name :: operator op( arg-list)
{
function body
}
Where return type is the type of value returned by the specified operation and op is the operator being
overloaded. The op is preceded by the keyword operator, operator op is the function name.
Operator functions must be either member function, or friend function. A basic difference between them
is that a friend function will have only one argument for unary operators and two for binary operators, while a
member function has no arguments for unary operators and only one for binary operators. This is because the
object used to invoke the member function is passed implicitly and therefore is available for the member
functions. But in the case of Friend functions, Arguments may be passed either by value or by reference.
operator functions are declared in the class using prototypes as follows:-
vector operator + (vector); // vector addition
vector operator-( ); //unary minus
friend vector operator + (vuelor, vector); // vector add
friend vector operator -(vector); // unary minus
vector operator - ( vector &a); // substraction
int operator = =(vector); //comparision
friend int operator = =(vector ,vrctor); // comparision
Operator overloading… Cont’d
Vector is a data type of class and may represent both magnitude and direction or a series of points called elements.
The process of overloading involves the following steps:-
1. Create a class that defines the data type that is used in the overloading operation.
2. Declare the operator function operator op() in the public part of the class
It may be either a member function or friend function.
3. Define the operator function to implement the required operations.
Overloaded operator functions can be invoked by expressions such as
op x or x op;
for unary operators and
x op y
for binary operators. Op x (or x op) would be interpreted as either
operator op(x);
for friend functions. Similarly, the expression x op y would be interpreted as either
x. operator op (y)
In case of member functions, or
operator op (x, y);
in case of friend function. When both the forms are declared , standard argument matching is applied to
resolve any ambiguity.
Operator overloading… Cont’d
Note: Here the argument is passed by reference. It will nor work if we pass argument by value because
only a copy of the object that activated the call is passed to operator-(). Therefore, the changes made
inside the operator function will not reflect in the called object.
Int main()
Operator overloading… Cont’d
{
Overloading Binary Operators complex C1, C2, C3; // invokes constructor 1
C1 = complex(2.5, 3.5); // invokes constructor 2
Below program illustrates the Binary Operator overloading using Operator+() function C2 = complex(1.6, 2.7);
#include <iostream>
Using namespace std: C3 = C1 + C2; // invokes operator+() function
Class complex
{ cout << “C1 = “; C1. display();
cout << “C2 = “; C2. display();
float x; //real part cout << “C3 = “; C3. display();
float y; // imaginary part
public: return 0;
complex() { } // Constructor 1 }
complex(float real, float imag) // Constructor 2
Output:
{ C1 = 2.5 + j3.5
x = real; C2 = 1.6 + j2.7
y = imag;
C3 = 4.1 + j6.2
}
complex operator+(); // overload unary operator Note: Consider the function operator+(); its having following features. 1. It receives only one complex type
void display(void); argument explicitly.
}; 2. It returns a complex type value
3. It is a member function of complex.
complex complex :: operator+(complex c)
{ The function is expected to add two complex values and return a complex value as the result, but receives
complex temp; only one value as argument. The values come from C3 = C1 + C2
temp.x = x + c.x;
temp.y = y + c.y; A member function can be invoked only by an object of the same class. Here, the object C1 takes the
return (temp); responsibility of making the function and C2 plays the role of an argument that is passed to the function.
The above invocation statement is equivalent to C3 = C1.operator+(C2).
} Therefore, in the operator+() function, the data members of C1 are accessed directly and the data
void complex :: display(void) members of C2 (that is passed as an argument) are accessed using dot operator. Thus both objects are
{ available for the function. For example, in the statement temp.x = x + c.x;
cout << x << “ + j “ << y << “\n”;
} c.x refers to the object C2 and x refers to the object C1.temp.x is the real part of temp that has been
created specially to hold the results of addition of C1 and C2. The function returns the complex temp to be
assigned to C3.
Operator overloading… Cont’d
1. Only existing operators can be overloaded. New operators can not be created.
2. The overloaded operator must have at least one operand that is of user-defined type.
3. We cannot change the basic meaning of an operator. That is to say, we cannot redefine the plus(+)
operator to subtract one value from the other.
4. Overloaded operators follow the syntax rules of the original operators. They cannot be overridden.
5. There are some operator that cannot be overloaded.
6. We cannot use friend functions to overload certain operators. However, member functions can be
used to overload them.
7. Unary operators, overloaded by means of a member function, take no explicit arguments and
return no explicit values, but, those overloaded by means of a friend function, take one reference
argument (the object of the relevant class).
8. Binary operators overloaded through a member function take one explicit argument and those
which are overloaded through a friend function take two explicit arguments.
9. When using binary operator overloaded through a member function, the left hand operand must
be an object of the relevant class.
10. Binary arithmetic operators such as +, _, * and / must explicitly return a value. They must not
attempt to change their own arguments.
Type Conversions
In a mixed expression, constants and variables are of different data types. The assignment operations
causes automatic type conversion between the operand as per certain rules.
The type of data to the right of an assignment operator is automatically converted to the data type of
variable on the left.
we can also use the assignment operator in case of objects to copy values of all data members of right
hand object to the object on left hand. The objects in this case are of same data type. But of objects are of
different data types we must apply conversion rules for assignment. (Example: The statement C3 = C1 + C2
in Binary Operator overloading.)
There are three types of situations that arise where data conversion are between incompatible types.
After this conversion, the hrs member of T1 will contain value of 1 and mins member contain a value of 25, denoting 1 hours and
25 minutes.
Note that the constructors used for the type conversion take a single argument whose type is to be converted.
In both the examples, the left-hand operand of = operator is always a class object. Hence, we can also accomplish this conversion
using an overloaded = operator.
Type Conversions …. Cont’d
Both the above statements have exactly same effect. When the compiler encounters a statements that requires the conversion
of a class type to a basic type, it quietly calls the casting operator function to do the job.
Since it is a member function, it is invoked by the object and therefore, the values used for, Conversion inside the function
belongs to the object that invoked the function. This means that the function does not need an argument.
In the string example discussed earlier, we can do the conversion from string to char* as follows:
String :: operator char*( )
{
return (p) ;
}
Type Conversions …. Cont’d
objX is an object of class X and objY is an object of class Y. The class Y type data is converted to the class X type
data and the converted value is assigned to the objX. Since the conversion takes place from class Y to class X, Y is
known as the source class and X is known as the destination class.
Such conversion between objects of different classes can be carried out by either a constructor or a conversion
function. The compiler treat them the same way and which one to use, depends upon where we want the type-
conversion function to be located in the source class or in the destination class.
Let us consider a single-argument constructor function which serves as an instruction for converting the
argument's type to the class type of which it is a member. This implies that the argument belongs to the source
class and is passed to the destination class for conversion. This makes it necessary that the conversion
constructor must be placed in the destination class.
Here is the summary of all the three conversions. It shows that the conversion from a class to any other type
(or any other class) should make use of a casting operator in the source class. On the other hand, to perform
the conversion from any other type/class to a class type, a constructor should be used in the destination class.
When a conversion using a constructor is performed in the destination class, we must be able to access
the data members of the object sent (by the source class) as an argument. Since data members of the source
class are private, we must use special access functions in the source class to facilitate its data flow to the
destination class.
Function Overloading
Overloading refers to the use of the same thing for different purposes . C++ also permits overloading of
functions .This means that we can use the same functions that perform a variety of different tasks. This is known
as function polymorphism in oops.
Using the concepts of function overloading, we can design a family of functions with one function name but
with different argument lists in the functions call . The function would perform different operations depending on
the argument list in the function call. The correct function to be invoked is determined by checking the number
and type of the arguments but not on the function type.
For example an overloaded add() function handles different types of data as shown below.
//Declaration
int add(int a, int b); //prototype 1
int add (int a, int b, int c); //prototype 2
double add(double x, double y); //prototype 3
double add(int p, double q); //prototype 4
double add(double p , int q); //prototype 5
//function call
cout<<add(5,10); //uses prototype 1
cout<<add(15,10.0); //uses prototype 4
cout<<add(12.5,7.5); //uses prototype 3
cout<<add(5,10,15); //uses prototype 2
cout<<add(0.75,5); //uses prototype 5
A function call first matches the prototype having the same number and type of arguments and then calls the
appropriate function for execution.
Function Overloading….Cont’d
1. The compiler first tries to find an exact match in which the types of actual arguments are the same and use that
function .
2. If an exact match is not found the compiler uses the integral promotions to the actual arguments such as :
char to int
float to double to find a match
3. When either of them tails ,the compiler tries to use the built in conversions to the actual arguments and them uses
the function whose match is unique . If the conversion is possible to have multiple matches, then the compiler
Example:
long square (long n);
double square(double x);
A function call such as square(10); Will cause an error because int argument can be converted to either long
or double .There by creating an ambiguous situation as to which version of square( ) should be used.
4. If all the steps fails, then the compiler will try the user-defined conversions in combination with integral promotions
and built-in conversions to find a unique match. User-defined conversions are oftern used in handling class objects.
Function Overloading….Cont’d
int volume(int);
double volume( double , int ); //Function Declaration (Prototype)
long volume(long ,int ,int);
main( )
{
cout << volume(10) << “\n”;
cout << volume(2.5, 8) << “\n”; //main function
cout<<volume(100L,75,15) << “\n”;
Return 0;
}
int volume( int s) //cube
{
return (s*s*s);
}
output:
double volume( double r, int h) //cylinder 1000
{ // Function Definitions 157.26
return(3.1416*r*r*h); 112500
}
long volume (long l, int b, int h) //rectangular box
{
return(l*b*h);
}
Inheritance
Reusability is yet another feature of OOP’s. For instance, the reuse of a class that has already been
tested, debugged and used many times can save us the effort of developing and testing the same again.
C++ strongly supports the concept of reusability. The C++ classes can be reused in several ways. Once a
class has been written and tested, it can be adopted by another programmers to suit their requirements.
This is basically done by creating new classes, reusing the properties of existing ones. The mechanism of
deriving a new class from an old one is called inheritance (or derivation). The old class is called base class
and the new one is called the derived class or subclass.
The derived class inherits some or all the properties from the base class. A class can also inherit
properties from more than one class or from more than one level. A derived class with only one base class is
called single inheritance and one with several base classes is called multiple inheritance. On the other
hand, the properties of one class may be inherited by more than one class is known as Hierarchical
inheritance. The mechanism of deriving a class from another ‘derived class’ is known as Multilevel
inheritance.
Inheritance… cont’d
• When a base class is privately inherited by a derived class, ‘public members’ of the base class become
‘private members’ of the derived class and therefore the public members of the base class can only be
accessed by the member functions of the derived class. They are inaccessible to the objects of the
derived class.
• On the other hand, when the base class is publicly inherited, ‘public member’ of the base class become
the ‘public member’ of the derived class and therefore they are accessible to the object of the derived
class.
• In both the cases, the private members are not inherited and therefore, the private members of a base
class will never become the member of its derived class.
• In inheritance, some of the base class data elements and member functions are ‘inherited’ into the
derived class. We can add our own data and member functions and thus extend the functionality of the
base class. Inheritance, when used to modify and extend the capabilities of the existing classes, becomes
a very powerful tool for incremental program development.
Single Inheritance
Below program illustrates single Inheritance. Here the base class int B :: get_a()
B and a derived class D. The class B contains one private data member, {
return a;
one public data member, and three public member functions. The class }
D contains one private data member and two public member
functions. void B :: show_a()
#include <iostream> {
cout << “a=“ << a << “\n”;
Using namespace std: }
Class B void D :: mul()
{ {
c = b * get_a();
int a; // private; not inheritable
}
public: void D :: display()
int b; // public; ready for inheritance {
void get_ab(); cout << “a=“ << get_a() << “\n”;
cout << “b=“ << b << “\n”;
int get_a(void); cout << “c=“ << c << “\n\n”;
void show_a(void); }
}; Int main()
{
class D : public B // public derivation D d;
{ d.get_ab();
int c; d.mul(); Output:
d.show_a();
public: d.display(); a = 5
void mul(void); a = 5
void display(void); d.b = 20; b = 10
d.mul();
} d.display();
c = 50
void B :: get_ab(void)
{ return 0; a = 5
a = 5; b = 10; } b = 20
} c = 100
Single Inheritance…Cont’d
The class D is a public derivation of the class B. Let us consider the case of private derivation
Therefore, D inherits all the public members of B and retains class d : private B // Private derivation
their visibility. Thus a public member of the base class B is also {
a public member of derived class D. The private member of B
int c;
cannot be inherited by D. Here is the class D
public:
void mul(void);
void display(void);
}
A private data member can be inherited by modifying the visibility limit of the private member by making it public. This is make it
accessible to all the other functions of the program, thus taking away the advantage of data hiding.
C++ provides a third visibility modifier, protected, which serve a little purpose in the inheritance. A member declared as protected is
accessible by the member functions within its class and any class immediately derived from it. It cannot be accessed by functions outside
these two classes.
A class can now use all the three visibility modes as illustrated below:
class alpha
{
private: //optional
---------- //visible to member functions within its class
protected:
---------- //visible to member function of its own and derived class
public:
----------- //visible to all functions in the program
};
• When a base class is (both public and private members) in protected mode ( protected derivation)
Both public and private members of the base class become protected members of the derived class.
Making a Private Member Inheritable…Cont’d
The below table summarizes how the visibility of a base class members undergoes modifications in all the
three type of derivations.
The friend functions and the member functions of a friend class have direct access to both the private and
protected data of the base class
The member function of a derived class can directly access only the protected data, and they can access the
private data through the member function of the base class.
Making a Private Member Inheritable…Cont’d
Below diagram illustrates how the access control mechanism works in various situations
Multilevel Inheritance
In Multilevel Inheritance, a class is derived form another derived class. In the below diagram, The
class A serves as a base class for a derived class B, which in turn serves as a base class for the derived class
C. The class B is known as the Intermediate base class since it provides a link for the inheritance between
A and C. The chain ABC is called inheritance path.
Consider the following example. Assume that the test result of a batch of students are stored in three
different classes. Class student stores the roll-number, class test stores the marks obtained in two subjects
and the class result contains the total marks obtained in the test. The class result can inherit the details of
the marks obtained in the test and the roll-number of student through multilevel inheritance.
Multilevel Inheritance… cont’d
#include <iostream> Void test :: get_marks(float x, float y)
{
Using namespace std: sub1 = x;
Class student sub2 = y;
{ }
protected: void test :: put_marks()
{
int roll_number; cout << “Marks in SUB1: “ << sub1<< “\n”;
public: cout << “Marks in SUB2: “ << sub2<< “\n”;
void get_number(int); }
Class result :: public test
void put_number(void); {
}; float total;
Void student :: get_number(int a) public:
void display(void)
{ };
roll_number = a; Void result :: display(void)
} {
total = sub1 + sub2;
void student :: put_number() put_number();
{ put_marks();
cout << “Roll Number: “ << roll_number << “\n”; cout << “ Total = “ << total << “\n”;
}
} Int main()
Class test :: public student {
{ result student;
student.get_number(111);
protected: Output:
student.get_marks(75.0, 59.5);
float sub1; student1.display(); Roll Number: 111
float sub2; Marks in SUB1: 75.0
public: return 0;
} Marks in SUB2: 59.5
void get_marks(float, float);
Total = 134.5
void put_marks(void);
};
Multiple Inheritance
A class can inherit the attributes of two or more classes. This is known as ‘multiple
inheritance’. Multiple inheritance allows us to combine the features of several existing classes
as a starring point for defining new classes. It is like the child inheriting the physical feature of
one parent and the intelligence of another. The syntax of the derived class is as follows:
Class D: visibility B-1, visibility B-2…
{
//body of D
}
Where, visibility may be either public or private.
The base classes are separated by commas.
Example:
class P : public M, public N
{
public:
void display(void);
};
Multiple Inheritance…Cont’d
class M Class P
{
protected: {
int m; protected:
public:
void get_m(int);
// from M Int m;
}; // from N Int n;
void M :: get_m(int x)
{
public: Void get_m(int);
m = x; // from M Void get_n(int);
} // from N Void display(void);
Class N // own member
{ };
protected:
int n; The member function display() can be defined as
public: follows:
void get_n(int);
};
Void P :: display(void)
void N :: get_n(int y) {
{
n = y; cout << “m = “ << m << “\n”;
} cout << “n = “ << n << “\n”;
The derived class P, as declared above , would, in effect,
contain all the members of M and N in addition to its own cout << “m*n = “ << m*n << “\n”;
members as shown below. };
Multiple Inheritance…Cont’d
include <iostream>
using namespace std;
Void P :: display(void)
class M {
{
protected: cout << “m = “ << m << “\n”;
int m; cout << “n = “ << n << “\n”;
public:
void get_m(int); cout << “m*n = “ << m*n << “\n”;
}; };
Class N
{
protected: int Main()
int n; {
public:
void get_n(int); P p;
}; p.get_m(10);
class P : public M, public N p.get_n(20);
{ p.display();
public:
return 0;
void display(void);
}; }
The base class will include all the features that are common to the subclasses. A subclass can
be constructed by inheriting the properties of the base class.
Hybrid Inheritance
There could be situations where we need to apply two or more types of inheritance to design a program. For
instance, consider the student result discussed in Multilevel Inheritance, assume that we have to give weightage for
sports before finalizing the results. The weightage for sports is stored in a separate class called sports.
The class, sports might look like
class sports
{
protected:
float score;
public:
void get_score(float)
void put_score(void);
};
The class, result will have both the multilevel and multiple inheritance and its declaration would be as follows
class result : public test, public sports
{
------------------
-------------------
};
Hybrid Inheritance… cont’d class sports
{
#include <iostream> protected:
Using namespace std: float score;
Class student public:
{ void get_score(float s)
protected: {
int roll_number; score = s;
public: {
void get_number(int a) void put_score(void);
{
{
cout << “Sports wt: “ << score << “\n”;
roll_number = a;
}
} };
void put_number(void) Class result :: public test, public sports
{ {
cout << “Roll Number: “ << roll_number << “\n”; float total;
} public:
Class test :: public student void display(void)
{ };
protected: Void result :: display(void)
{
float part1;
total = part1 + part2 + score;
float part2;
public:
put_number(); Output:
put_marks();
void get_marks(float x, float y) put_score();
Roll Number: 1234
{ cout << “ Total Score: “ << total << “\n”; Marks obtained
part1 = x; }
Int main()
Part1 = 27.5
part2 = y; { Part2 = 33.0
} result student;
Sports wt: 6
void put_marks(void) student.get_number(1234);
student.get_marks(27.5, 33.0); Total Score : 66.5
{ student.get_score(6.0)
cout << “Marks obtained: “ << “\n”; student1.display();
cout << “Part1 = “ << part1 << “\n”; return 0;
}
cout << “Part2 = “ << part2 << “\n”;
}
};
Virtual Base classes
We have just discussed a situation which would require the use of both multiple and multilevel inheritance. Consider
a situation, where all the three kinds of inheritance, namely multi-level, multiple and hierarchical inheritance, are
involved as shown in the below diagram.
The ‘child’ has two direct bass classes ‘parent1’ and
‘parent2’ which themselves has a common base class
‘grandparent’. The child inherits the traits of ‘grandparent’
via two separate paths. It can also inherit directly as shown
by the broken line. The grandparent is sometimes referred
to as indirect base class.
The inheritance by the child might pose some problems. All the public and protected members of ‘grandparent’ are
inherited into ‘child’ twice, first via ‘parent1’ and again via ‘parent2’. This means, ‘child’ would have duplicate set of
the members inherited from ‘grandparent’. The duplication of the inherited members can be avoided by making
common base class as the virtual base class while declaring the direct or intermediate base classes as shown below
class A // grandparent class B2 : public virtual A // parent2
{ {
-------- ----------
}; };
class B1 : virtual public A // parent1 class C : public B1,public B2 // child
{ {
-------- ------- // only one copy of A will be inherited
}; };
Pointers
Every variable is a memory location in which the assigned values are stored and every memory
location has its address defined which can be accessed using ampersand (&) operator which
denotes an address in memory.
Consider the following program which will print the address of the variables defined
#include <iostream>
using namespace std;
int main ()
{
int var1;
char var2[10];
Output:
cout << "Address of var2 variable: "; Address of var1 variable: 0xbfebd5c0
cout << &var2 << endl; Address of var2 variable: 0xbfebd5b6
return 0;
}
Pointers… Cont’d
What are Pointers?
A pointer is a variable whose value is the address of another variable. Like any variable or
constant, you must declare a pointer before you can work with it.
The general form of a pointer variable declaration is type *var-name;
• type - The pointer's base type; it must be a valid C++ data type
• var-name - The name of the pointer variable
• * - The asterisk is used to declare a pointer. In this statement the asterisk is being used
to designate a variable as a pointer.
Following are the valid pointer declaration
int *ip; // pointer to an integer
double *dp; // pointer to a double
float *fp; // pointer to a float
char *ch; // pointer to character
The actual data type of the value of all pointers, whether integer, float, character, or otherwise,
is the same, a long hexadecimal number that represents a memory address. The only difference
between pointers of different data types is the data type of the variable or constant that the pointer
points to.
Pointers… Cont’d
How to use a pointer? Consider the variable declaration int var = 20;
• Define a pointer variable. Int *ip
• Assigning the address of a variable to a pointer using unary operator (&) which returns the
address of that variable. *ip = &var
• Accessing the value stored in the address using unary operator (*) which returns the value of the
variable located at the address specified by its operand. *ip point to the value 20
#include <iostream>
using namespace std;
int main () {
int var = 20; // actual variable declaration.
int *ip; // pointer variable
ip = &var; // store address of var in pointer variable
cout << "Value of var variable: ";
cout << var << endl;
// print the address stored in ip pointer variable
cout << "Address stored in ip variable: "; Output:
cout << ip << endl; Value of var variable: 20
// access the value at the address available in pointer Address stored in ip variable: 0xbfc601ac
cout << "Value of *ip variable: "; Value of *ip variable: 20
cout << *ip << endl;
return 0;
}
Pointers… Cont’d
Null Pointers
It is always a good practice to assign the pointer NULL to a pointer variable in case you do not
have exact address to be assigned. This is done at the time of variable declaration. A pointer that is
assigned NULL is called a null pointer.
The NULL pointer is a constant with a value of zero defined in several standard libraries,
including iostream. Consider the following program
#include <iostream>
using namespace std;
Output:
int main () { The value of ptr is 0
int *ptr = NULL;
cout << "The value of ptr is " << ptr ;
return 0;
}
On most of the operating systems, programs are not permitted to access memory at address 0
because that memory is reserved by the operating system. However, the memory address 0 has
special significance; it signals that the pointer is not intended to point to an accessible memory
location. But by convention, if a pointer contains the null (zero) value, it is assumed to point to
nothing.
Pointers… Cont’d
Thus, if all unused pointers are given the null value and you avoid the use of a null pointer, you can
avoid the accidental misuse of an uninitialized pointer. Many times, uninitialized variables hold
some junk values and it becomes difficult to debug the program.
Pointers… Cont’d
Pointer Arithmetic
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. A limited set of arithmetic operations can
be performed on pointers which are:
• incremented ( ++ )
• decremented ( — )
• an integer may be added to a pointer ( + or += )
• an integer may be subtracted from a pointer ( – or -= )
• difference between two pointers (p1-p2)(Pointer comparison)
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.
Pointer Arithmetic … Cont’d
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
#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 << "] = ";
Output:
cout << ptr << endl;
Address of var[0] = 0xbfa088b0
cout << "Value of var[" << i << "] = "; Value of var[0] = 10
cout << *ptr << endl; Address of var[1] = 0xbfa088b4
// point to the next location Value of var[1] = 100
ptr++; Address of var[2] = 0xbfa088b8
} Value of var[2] = 200
return 0;
}
Pointer Arithmetic … Cont’d
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 −
#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 << "] = "; Output:
cout << *ptr << endl; Address of var[3] = 0xbfdb70f8
// point to the previous location Value of var[3] = 200
Address of var[2] = 0xbfdb70f4
ptr--;
Value of var[2] = 100
}
Address of var[1] = 0xbfdb70f0
return 0; Value of var[1] = 10
}
Pointer Arithmetic … Cont’d
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] −
#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; Output:
cout << "Value of var[" << i << "] = "; Address of var[0] = 0xbfce42d0
cout << *ptr << endl; Value of var[0] = 10
// point to the previous location Address of var[1] = 0xbfce42d4
ptr++; Value of var[1] = 100
i++; Address of var[2] = 0xbfce42d8
} Value of var[2] = 200
return 0;
}
Pointers… Cont’d
Pointers vs Arrays
Pointers and arrays are strongly related. In fact, pointers and arrays are interchangeable in
many cases. For example, a pointer that points to the beginning of an array can access that array by
using either pointer arithmetic or array-style indexing. Consider the following program −
#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; Output:
cout << "Value of var[" << i << "] = "; Address of var[0] = 0xbfa088b0
cout << *ptr << endl; Value of var[0] = 10
// point to the next location Address of var[1] = 0xbfa088b4
ptr++; Value of var[1] = 100
} Address of var[2] = 0xbfa088b8
return 0; Value of var[2] = 200
}
Pointers vs Arrays… Cont’d
However, pointers and arrays are not completely interchangeable. For example, consider the
following program −
#include <iostream>
using namespace std;
const int MAX = 3;
int main () {
int var[MAX] = {10, 100, 200};
#include <iostream>
using namespace std;
const int MAX = 3;
int main () {
int var[MAX] = {10, 100, 200};
int *ptr[MAX];
A variable that is a pointer to a pointer must be declared as such. This is done by placing an
additional asterisk in front of its name. For example, following is the declaration to declare a pointer to
a pointer of type int − int **var;
When a target value is indirectly pointed to by a pointer to a pointer, accessing that value requires
that the asterisk operator be applied twice, as is shown below in the example −
Pointers… Cont’d
Pointer to Pointer Example:
#include <iostream>
using namespace std;
int main () {
int var;
int *ptr;
int **pptr;
var = 3000;
// take the address of var
ptr = &var;
// take the address of ptr using address of operator &
pptr = &ptr;
// take the value using pptr Output:
Value of var :3000
cout << "Value of var :" << var << endl; Value available at *ptr :3000
cout << "Value available at *ptr :" << *ptr << endl; Value available at **pptr :3000
cout << "Value available at **pptr :" << **pptr << endl;
return 0;
}
Pointers… Cont’d
Passing Pointers to Functions
To pass a pointer to a function, simply declare the function parameter as a pointer type. There are 3 ways
to pass C++ arguments to a function:
• call-by-value
• call-by-reference with pointer argument
• call-by-reference with reference argument// C++ program to illustrate call-by-methods in C++
When the above code is compiled and executed, it produces the following result −
Constructor called.
Constructor called.
Volume of Box1: 5.94
Volume of Box2: 102
Managing console input /output operations
Every program takes some data as input and generate processed data as output following the
familiar input-process-output cycle. Therefore it is essential to know how to provide input data and
how to present the results in a desired form. C++ supports a rich set of I/O functions and operations
to do this.
C++ uses the concept of stream and stream classes to implement its I/O operations with the
console and disk files.
C++ streams:
A stream is a sequence of bytes. It acts either as a source from which the input data can be
obtained or as a destination to which the output data can be sent. The source stream that provides
data to the program is called the input stream and the destination stream that receives output fron
the program is called output stream. In the other words, a program extracted the bytes from an
input stream and inserts bytes into an output stream as shown below
C++ streams…Cont’d
The data in the input stream can come from the keyboard or any other storage device. Similarly
the data in the output stream can go to the screen or any other storage device. The stream acts as
an interface between the program and the input/output device. Therefore, a C++ program handles
data independent of the devices used. C++ contain several pre-defined streams that are
automatically opened when a program begins its execution. These includes cin and cout.
C++ stream classes:
The C++ I/O system contains a hierarchy of classes that are used to define various streams to
deal with both the console and disk files. These classes are called stream classes Below diagram
shows the hierarchy of the stream classes used for input and output operations with the console
unit. These classes are declared in the header file iostream. The file should be included in all
programs that communicate with the console unit.
C++ stream classes…Cont’d
As seen in the above diagram, ios is the base class for istream (input stream) and ostream
(output stream) which are, in turn, base classes for iostream(input/output stream). The class ios is
declared as the virtual base class so that only one copy of its members are inherited by the
iostream.
The class ios provides the basic support for formatted and unformatted I/O operations. The
class istream provides the facilities for formatted and unformatted input while the class
ostream(through inheritance) provides the facilities for formatted output. The class iostream
provides the facilities for handling both input output streams. Three classes namely
istream_withassign, ostream_withassign and iostream_withassign add assignment operators to
these classes.
C++ stream classes…Cont’d
Stream classes for console operations:
The operator >> reads the data character by character and assigns it to the indicated location.
The reading for a variable will be terminated at the encounter of a white space or a character that
does not match the destination type. For example consider the following code
int code;
cin>> code;
Suppose the following data is entered as input
4258D
The operator will read the characters upto 8 and the value 4258 is assigned to code. The
character D remains in the input streams and will be input to the next cin statement. The general
form for displaying data on the screen is
cout << item1 << item2 << ………… << itemN
The items item1 through itemN may be variables or constants of any basic type..
Unformatted I/O Operations…Cont’d
Program to illustrate the use of put() and get(), character handling functions:
#include <iostream>
using namespace std;
int main()
{
int count=0;
char c;
cout<<”INPUT TEXT \n”;
cin.get( c );
while ( c 1=’\n’ )
{
cout.put( c);
count++; Input
cin.get( c ); Object oriented programming
} Output
cout<< “\n Number of characters =” <<count <<”\n”; Object oriented programming
Return 0; Number of characters=27
Unformatted I/O Operations…Cont’d
During fist run, the newline character ‘\n’ at the end of “Delhi” which is waiting in the input queue
is read by the getline() that follows immediately and therefore it dos not wait for any response to the
prompt ‘enter city name again’. The character’\n’ is read as an empty line.
During the second run, the word “Delhi”(that was not read by cin ) is read by function getline()
and, therefore, here again it does not wait for any input to prompt ‘Enter city name again:”. Note that
the line of text “Greater Mumbai” is correctly read by the second cin.getline(city, size); statement.
The write() function displays an entire line and has the following form:
cout.write(line, size)
The first argument line represents the name of the string to be displayed and the second argument size
indicates the number of characters to display. Note that it does not stop displaying the character
automatically when the null character is encountered. If the size is greater than the length of line, then
it displays beyond the bound of line.
C++ supports a number of features that could be used for formatting the output. These
features include:
• ios class function and flags.
• Manipulators.
• User-defined output functions.
The ios class contains a large number of member functions that would help us to format the
output in a number of ways. The most important ones among them are listed below
Function Task
Width() To specify the required field size for displaying an output value
precision() To specify the number of digits to be displayed after the decimal point
of float value
fill() To specify a character that is used to fill the unused portion of a field
setf() To specify format flags that can control the form of output display
(such as left-justification and right-justification)
unsetf() To clear the flags specified
Formatted Console I/O Operations…Cont’d
Manipulators are special functions that can be included in the I/O statements to alter the
format parameter of stream. Below table shows some important manipulator functions that are
frequently used. To access these manipulators, the file iomanip should be included in the program.
In addition to these standard library manipulators, we can create our own manipulator functions to
provide any special output formats.
End of Unit II