Você está na página 1de 122

MODULE-1

Introduction to object Oriented Programming


Objectives:
1. Software Evolution
2. A look at Procedure Oriented Programming
3. Drawbacks of Procedure Oriented Programming
4. Object Orientation
5. Benefits of Object orientation
Key points:
 Software Evolution
• Evolution of Software Technology can be compared to the growth of a tree.
• Like a tree the software evolution has distinct phases or layers of growth.
• Layers of computer software.

1,0

Machine Language

Assembly Language

Procedure Oriented

Object Oriented Programming


• These layers were built up one by one over the last five decades with each
layer representing an improvement over the previous one
• If we consider the life of these layers in case of software systems each of the
layers continues to be functional whereas in the case of trees only the upper
most layer is functional.
 Procedure Oriented Programming
• Conventional Programming using high-level languages such as COBOL,
FORTRAN and C is commonly known as Procedure Oriented Programming
(POP).
• Procedure Oriented Programming views the problem as a sequence of things to
be done such as reading, calculating and printing.
A typical program structure for procedure oriented programming
Main Program

Function-1 Function-2 Function-3

Function-4 Function-5

Function-6 Function-7 Function-8

• Relationship of data and functions in Procedure oriented programming

Global Data Global Data

Function-1 Function-1 Function-1

Local Data Local Data Local Data

•Global data can be accessed by all functions


•Difficulties arise with global data
a. Uncontrolled modification
b. Poor maintainability and enhancement
If a programmer wants to add some features or to make some modification
to the existing feature the new code could modify some unprotected data. If
this modification is inappropriate some part of the program working
satisfactorily may stop to do so.
 Other drawbacks of Procedure oriented Programming
• Lack of specification
When a structure is defined only the structure of the record is defined, the
Operations that are to be performed on a variable is left unspecified.
• Low modularity
The presence of global data permits common data coupling between
procedures. Whenever the coupling is strong a change in one part of the
program affects other parts of the program.
• Poorly identifiable Components
In programs written using block structural languages it is difficult to identify
Components, which form one unit.
• Strongly Typed Identifier
Functions are highly dependent on the type of variables that are being used. This
Property hinders reusability.
 Object Orientation
OOP allows decomposition of a problem into number of entities called
objects and then builds data and functions around these objects. The data of an
object can be accessed only by the functions associated with that object that is
data is local to an object. Objects can be used in different programs without
modifications.
Organization of data and functions in OOP
Object A Object B

Data Data

Functions Communication Functions

Object C

Functions

Data

 Benefits of Object Orientation

• No accidentals modification of data


No external object can access the data of any object, which is local to it. No
data is global.
• High Specification Level
It is possible to associate meaningful operation with an object
For example an object can be defined whose data is a list of employee and
with operations like ‘Compute Salary’, ‘ Print Payroll’ etc. Thus the level of
specification is high.
• Easier Maintenance
The visible part of an object is its operation. The manner in which an object
implements its operation is internal to it. Therefore any change within an
object would not affect external objects. That is system built using objects is
resilient to change. Thus it is easier to maintain programs.
• High level of Modularity
Each object can be viewed as a module. There is no common data
between objects. Therefore there is no common data coupling. The only
interaction between objects is through the functions defined in each object.
Thus the modules are loosely coupled that means high level of modularity.
• Reuse
Each object is well-defined unit of data and operations. Thus objects
can be easily identified and used in other applications.

 Conclusion

An object binds the data structure and the operations so that accidental modifications
to data are avoided. Programs are easily maintainable resilient to change and more
secure. Object reuse provides benefits to the programmer.

 Questions

1. Define object oriented programming?


2. Compare object oriented programming with procedure oriented
programming.
3. Drawbacks of procedure oriented programming
4. Benefits of object orientation.
5. Why object oriented programming approach is the preferred form of
programming over other approaches.

OBJECT
Objectives
 Object concepts
 Object views
 Structure of an object
 Message
 Instance variables
 Types of objects
 Encapsulation
Key points
 Object definition
• It is a concept, abstraction or thing with crisp boundaries and meaning for the
problem at hand.
• It is a collection of operations, which share a state.
• All objects have identity and are distinguishable
For example
1. Two apples with same color shape and texture are still individual apples.
2. A paragraph in a document, a person, a place etc.
• Operation –Two parts
1. Interface
o Defines the message to which an object responds
o Specifies signature of the operation
Signature consists of
a) Name of operation
b) Parameters and their types
c) Return value
2. Implementation
Contains the procedure, which is to be executed to respond to a message.
 Object views
• Outside view
o Parts of the object, which is seen by other objects.
o Consists the interface of the operations
• Inside view
• Implementation of its operations shared data or state of an object.
 Schematic diagram of an object

State
OP1
Interface OP2 Implementations
OP3 of
OP1, OP2, OP3

OP1, OP2, OP3-Operations

Example : Consider the object point


Object name : Point
Instance variables : x , y
Operations : get_x() , get_y()

x,y
get_x() Implementations
of
get_y() get_x() , get_y()

 Message

• It is a request for execution of a procedure


• An object sends a message to another object when it wants some service from
the second object
• Message involves name of the object, name of the function and the
information to be sent

Example: employee. salary (name).


Name of the object : employee
Name of the function : salary
Information to be sent: name

 Instance variables

• Variables representing the state of an object are called instance variables.


• Also referred to as attributes.
• Instance variables are local to an object. Thus two objects can have the same
name for an instance variable.
• Different objects can have same or different values for a given instance
variable.
• The variables can be of atomic type (simple object) or may reference other
objects (complex object).
Example:
The objects book and magazine may both have an instance variable called year.

Complex objects
Objects containing other objects are called complex or aggregate objects.
Example:
Consider a ‘washing machine’. It consists of a ‘drum’ and a ‘motor’. Drum and
motor can be considered as objects.

Drum
Main object

Washing Component objects


Machine

Motor

 Component object
The objects, which are contained in another object, are called as
component objects.
In the above example drum and motor are component objects.
Component objects are of two types.
a. Dependent component object
The components may have no existence unless the aggregate object of
which they are a part also exists.
Example:
‘Body’ and ‘Chassis’ are part of a ‘car’ and have no existence without the car.
Independent component object
The component object, which have independent existence.
Example:
The object “manufacturer” which is a component of a “car” can exist
independently of the car.

 Hierarchy of aggregate objects

Car

Chassis Body Manufacturer

Door Interior

State
• The state of an object at a given instance of time is determined by the values
taken on by the instance variables of the object.
• Incase the object is a complex object then the state is determined by the values
taken on by the simple variables and those taken on by the component objects.
• The rule is recursively applied for the component objects till simple variables
are arrived at.
Example:
Consider a simple object “Book” which has title, author, acc_no, year and availability
as instance variables. Let the values taken by the variables at some instance of time be
Title -OOP
Author -001.624
Year -2000
Availability -True

Operations

Definition
The operation, which forms the interface of an object, may perform
different kinds of functions.
Main categories
a. Modifier: Alters the state of an object
b. Selector: Allows accessing the state of an object.
Example:
Object : account
Instance variables : acc_no, name, balance
Operations : withdraw(value), deposit(value), get_bal()
• Here the operations deposit() and withdraw() change the values in the
variable balance and therefore alter the state of the object. These two
operations are modifiers.
• The state of an object is only accessed using get_bal() operation. Therefore
get_bal() is a selector.

Withdraw(value) Acc_no,name
Deposit(value) balance
Get_bal()

implementations

 Conclusion
Objects are the basic run time entities in an object oriented
systems.When a program is executed the objects interact by sending messages to one
another. Attributes of objects are the instance variables. The state of an object at a
given instance of time is determined by the values taken on by the instance variables
of the object. Operations are categorized in to two groups which are modifier and
selector. Modifier alters the state of an object. Selector allows only accessing the
state of an object.

 Questions

1. What is an object?
2. What kinds of things can become objects in OOP?
3. What are different types of objects and explain each with example?
4. Explain the terms operation, message, and instance variables?

Class

Objectives

 Class definition
 Class stucture
 Encapsulation
 Persistence
 Object Identity
Key Points

 Class definition

•A set of objects which have the same structure and behavior or it is a collection
of objects of similar type.
Example of a class.
Mango, apple and orange are members of the class fruit.
• Class creates objects which is called instance of that class.
Syntax for creating an object.
Example
If fruit has been defined as a class then the statement
Fruit mango;
will create an object mango belonging to the class fruit.
• A class has two parts
1. Interface
2. Implementation
• Class may be specified as
Name
Attributes
Operations
Example:
The class Account with the attributes and operations is given below.
Name:
Account
Attributes:
Acc_no
Name
Balance
Operations:
Withdraw(am)
Deposit(am)

 Class structure

Class-name

Attribute-name-1:data type-1==default value-1


Attribute-name-2:data type-2==default value-2

Operation-name-1(argument-list-1):result-type-1
Operation-name-2(argument-list-2):result-type-2

class variables are common to all the instance of the class. There is only one copy of the
class variable (data members).
A class operation is an operation on the class itself (member functions).
 Implementation of a class

Instance of A

Operations
Variables Class A
Class variables Instance variables
Class operations
An instance X of the class A is created by the class operations defined for
A. The instance X when created has a copy of the instance variables and a
pointer to its class. When X receives a massage to execute an operation then
the operations defined in its class are searched. If it is found, it is executed.
Otherwise an error is signaled.
Encapsulation
• The wrapping up of data and functions into a single unit (called class) is known
as encapsulation.
• Encapsulation (information hiding), separates the outside view of an object from
the inside view.
Advantages of encapsulation
Programs are immune to any changes made by the implementations.
Restriction of data access prevents accidental corruption of data making the programs
more reliable.

 Persistence
• Transient variables
In programming languages like C program variables come in to
existence and their values are accessing only when the block in which they are
declared is executed. Up on exit from there, the variables automatically cease to
exist. These are called transient variables.
• Persistent object
In object orientation, when an object is created it occupies some space and exist
for a certain period of time. If the object transidents time then the object is a
persistent object else is a transient object.

 Object identity

Property of the object, which is determined by its existence. It is a unique identifier,


which help in identifying an object
Object identity is created and maintained at the system level.
 Conclusion

A class describes a group of objects with similar properties (attributes).Common


behavior(operation) and common relationship to other objects. Attribute is a data
value held by the objects or it is a variable, which is shared by all the other objects
of the class. Class operation is a function or transformation that may be applied to
or by objects in a class. The same operation may apply to many different classes.
An operation may have arguments.
Objects, which are available beyond the lifetime of the process, which creates
them, are persistent objects. Transient objects have existence within a block which
is defined is being executed. Object identity state that every object has a unique
identity, which helps in distinguishing one object from the other.
 Questions
1. Distinguish between objects and classes.
2. Define a class ‘Queue’; identify the instance variables and the operations
3. Define a class stack with push and operations. Identify other operations, which
may be meaningful.

Class Hierarchy
Objectives:
 Inheritance
 Overriding
 Polymorphism

Key points
 Inheritance definition
Inheritance is the process by which object of one class acquire the
properties of object of another class acquire the properties of objects of
another class. It supports the concepts of hierarchical classifications.
Hierarchical classification- generalization/specialization relationship.

Bird
Attributes
Feather
Lay eggs

Flying bird Nonflying bird

Attributes Attributes
---------- ……………..
………. ……………..

Robin Swallow Penguin Kiwi

Attributes Attributes Attributes Attributes


…………. ………….. ………….. ………….
…………. ………….. ………….. ………….
Super class
• The class being refined is called super class.
• A generalized class is referred to as super class.
Subclass
• Refined version of the super class is the subclass.
• Subclass inherit the features of super class.
• Also called specialized class
• Sub class is permitted to add its own behavior.

Advantages of inheritance
• Reusability
• Redundancy can be avoided
Example: common data and behavior of different kind of student is not repeated in each
class but is defined us only one place, the class student
• Help us reducing complexity
• W hen modification are to be effected then changes have to be effected in only
one place
Implementation of inheritance

Class A Instance of A

Operations of A Class A
Variables of A Instance variables

B Subclass of A Instance of B
Class B
Inherits from A Inherited instance
Operations of B Variables of A
Variables of B Instance variables of B

Consider two classes class A and class B class A is the super class and class B is the
subclass. The instance of A, a has a private copy of the instance variables defined in A
and a pointer to its class where the operations are defined. Class B defines the
instanceVariable and operation relevant to that class .An instance of B (b), has a private
copy of instance variable defined in B. There is a pointer from the B to the class A When
an operation is invoked for an instance b of B ,first the method is searched for in B. if it
is found then it is executed using the instance variables of b. if not ,then theSearch
continues in A , the super class of B. if it is found in A ,then the method is Executed
using the data defined in b.
Substitutability

An instance of the super class can be substituted by an instance of the subclass. An object
of the specialized class is a subject of the generalized class.

Overriding

Implementation of an operation may vary along the hierarchy of class. A sub class is
permitted to over ride the features defined in the super class, by defining the name of a
variable or operation identical to that in the super class. The over riding mechanism does
not permit features of the super class to be cancelled by the sub class it permit the
specification of the variables to be tightened and the operation to have a difficult
implementation in the sub class.
Over riding is done for the following reason

Overriding for extension

The new operation is the same as the inherited operation, except it adds some behavior,
Usually effecting new attributes of the sub class .

Example: window class may have a draw operation that draws the window boundary and
Contents. Windows could have a sub class labeled window that class has a draw
operation.The draw-labeled window method would be implemented by invoking the
method to draw a window and then adding code to draw the label.
Overriding for restriction
This may be necessary to keep the inherited operation closed within the subclass.
Example
The super class set may have the operation add(subject). The subclass Integerset would
then have more restrictive operation add(integer).
Overriding for optimization
The new method must have the same external protocol and results as the old one but its
internal representation and algorithm may differ completely.
Example
Super class Integerset could have an operation to find the maximum integer. It may be
implemented as a sequential search. The subclass SortedIntegerset could provide a more
efficient implementation of the maximum integer operation, since the contents of the set
are already sorted.
Overriding for convenience
The new class is made a subclass of the existing class and overrides the methods that are
inconvenient.
Polymorphism
It is the ability to associate more than one implementations with the same operation. The
word ‘poly’ is from Greek word meaning ‘many’ and ‘morphism’ is also from Greek
meaning ‘form’. It means the ability to take more than one form. Polymorphism can exist
in two ways. Compile time polymorphism and runtime polymorphism that is static
binding or early binding and dynamic binding or late binding. In C++ polymorphism
appears in three entities.
1) operators 2) functions 3) objects

Hierarchy dependent
An operation defined in the super class can have any number of implementations along
the class hierarchy. This type of polymorphism is referred to as universal polymorphism
or overriding.
Hierarchy independent
The same name of an operation has different implementations in different classes and
these classes need not be related by class hierarchy. This takes the form of overloading
which is also referred to as Ad Hoc Polymorphism.
Overloading
Operator overloading
Function overloading
The process of sharing the same name by two or more functions is referred to as function
overloading.
Example:
Consider the classes person and monument defined below.
Name:
Person
Attributes:
Age
Operations:
Less_age(person)
Name:
monument
Attributes:
Age
Operations:
Less_age(monument)
Here the name less_age is overloaded to have more than one mapping, one where the
ages of instances of person is compared and the other where the ages of instance of
monuments is compared.
Advantages of overloading
The user need not remember different names for the same operations in different classes.
Binding of operations
The linking of a procedure call to the code to be executed in response to the call.
a. Static binding(early binding)
• The class of the object is known at compile time.
• Overloading supports static binding.
Overloaded functions are selected for invoking by matching the type and number of
parameters. This information is available to the compiler at compile time and therefore is
able to select the required function for a particular call during the compile time itself.
b. Dynamic binding(late binding)
• Information is available only when the procedure is called that is only at run
time.
• The binding of the message to an actual implementation is done dynamically.
• The code associated with a given procedure call is not known until the time of
the call at run time.
Conclusion
Inheritance is concerned with defining a hierarchy relationship among classes. The major
advantage of inheritance is reuse. Polymorphism is the ability to associate more than one
implementation with the same operation. Polymorphism takes two different forms
overloading and overriding. The difference between overloading and overriding are
(1)overriding is for classes which are in a hierarchy and overloading is for classes which
may be independent a hierarchy. In overriding the subclass may choose not to re-
implement an inherited operation and the operations can be for an instance of the
subclass. In overloading every class must have an implementation.
Questions
1. Consider the following classes which together provide essential nutrients
banana, wheat, fish blackgram, millk, spinach, egg, orange, rice, potato, meat
arrive at agood hierarchy.
2. Describe inheritance, reusability.
3. Explain polymorphism and overloading with example.
4. Distinguish between the following terms
5. Objects and classes
6. Inheritance and polymorhism
7. What are the advantages of inheritance.

Abstract Class & Multiple Inheritance

Objectives:
 Abstract class
 Types of inheritance
 Multiple inheritance

Key points
 Abstract class
• A super class just describes the interface and leaves some or all the
implementations to the sub class.
• An instance of an abstract class is never created.
• An abstract class is designed to have sub classes which override the
implementations.
• It provides a base upon which other classes may be built.
Example:
The function draw is never really implemented in the class shape.
 Types of inheritance
• Single Inheritance
When a subclass inherits only from one base class it is known as single
inheritance.

X Base class

Y Sub class

• Multiple Inheritance

When a sub class inherits from multiple base class it is known as


multiple inheritance.

X Y

• Hierarchical Inheritance

When many subclass inherit from a single base class it is known as hierarchical
inheritance.

Baseclass
Z

W X Y

Sub classes

• Multilevel inheritance
When a sub class inherits from a class that itself inherits from another class it is known as
multilevel inheritance.
X Base class of Y

Y Subclass of X & Baseclass of Z

Z Sub class of Y

• Hybrid Inheritance

When a sub class inherits from multiple base classes and all of its base classes inherit
from a single base class this form of inheritance is known as hybrid inheritance.

X Y

 Multiple inheritance

• In multiple inheritance a sub class inherits from more than one super class.
Example

student faculty

TA
In a teaching institute there are students, faculty and teaching assistants.
Teachingassistants are students but have the role of a teaching faculty as well. The class
TA can be designed by inheriting the behaviour from the two classes, student and faculty.
That is the assistant should have two super classes which is multiple inheritance.

• The syntax of a derived class with multiple base classes

Class TA : Public faculty, private student


{
----------
----------
};
• Ambiguity

Whenever a class inherits from more than one super class there can be a conflict among
attributes as well as operations. That is an attribute or an operation can be defined with
the same name in more than one super class.

a) Attribute Ambiguity
Example

There are two base classes made-of-paper printed-matter, with the following attributes.
Name:
Made-of-paper
Attributes:
Length
Breadth
Thickness
Book is made of paper and is indeed printed. So if Book were to be a subclass of both
then it would inherit length from both the super classes. If the length in Book is to be
considered then it is not at all clear as to which attribute it refers to.
b) Operation Ambiguity
Example
Name:
Student
Attributes:
Gpa
Year
Operations:
Round(0
The operation round(0 is inherited by TA from both the super classes. If one were to send
the message round() to an instance of TA then it is not clear which of the two operations
are to be invoked.

• Resolving Ambiguity
User specified order
When the super classes are listed they are specified in a certain order (left-to-right).
Example:
Name:
TA
Super classes:
Student, faculty
Then a reference to year in TA will always refer to that in student.

Two implementations

1. The order in which the super classes are listed is very important.
2. If the operation to be used is to be a different one then the user has to explicitly
reorder the listing of the super class.
Example :
If round(0 in faculty is to be executed for an instance of TA then TA will have to be
redefined as
Name:
TA
Super classes:
Faculty, student
1. Consider that year in TA should refer to the one in student and round () to the one
in faculty. Using order of super class specification for ambiguity resolution, there
is no way in which this requirement can be expressed. Either year or round () have
to be both picked up from student or both from faculty.
2. Consider another situation that if the attribute year in both the super classes need
to be accessed, there is no way of specifying this. Explicit referencing handles
tjhis situation.
Explicit Reference

In explicit referencing the conflicting attribute or operation is qualified with the name of
the super class. Hence it is possible to access every conflicting attribute and operation
using the dot notation.
Example:
Year in student can be referred using
Student.year
 Conclusion

An abstract class is a super class just describes the interface and leaves all the
implementations to the sub class. An instance of an abstract class is never created. If a
subclass has only one super class then the inheritance is said to be single. In multiple
inheritance a sub class inherits from more than one super class. Conflicts arise in the case
of multiple inheritance where more than one super class can have the name of a variable ,
or operation. Different possible conflict resolution rules have been explained in this
section.
 Questions

1. What is an abstract class ? How it is different from class ?


2. Explain in detail about inheritance and multiple inheritance through an example.
3. What are abstract classes. Explain the role of abstract classes while building a
class hierarchy.
4. Explain multiple inheritance with suitable example.
5. What are different forms of inheritance supported by c++ ? Explain with
examples.

Object Oriented Design


Objectives

 The Design Process


Key points

• The object design phase determines the full definitions of the classes and
associations used in the implementations as well as the interfaces and algorithms
of the methods used to implement operations.
• The object design phase adds internal objects for implementations and optimizes
data structure and algorithms.
 Steps for design process
1. Identify the classes
2. Identify the semantics of the classes.
3. Identify the relationship among the classes.
4. Specify the interface and implementations of the classes.
Step one : Identify the classes

a. The first step is to identify the classes which are needed to solve the problem.
b. The purpose of identifying classes is to demarcate the problem problem domain.
Approaches to Identify the classes
i. Look at the English language description of the problem, and identify the nouns and
verbs.
ii. These nouns represent the possible classes for the design and the verbs, the
operations.
iii. Analyze the problem domain more closely and see whether all these nouns are
represented as classes.
iv. See the behavior of each class listed.
Example
Consider a library consisting of books and journals. These can be borrowed and
returned. Books can be renewed, journals can not be renewed. A book or journal has a
title. Books can be borrowed for a month, but journal can be borrowed for just a day.
1. The following nouns can be identified.
Library
Book
Journal
Title
2. While analyzing the problem domain it is found that the noun, library must be
deleted from the list as the library counter operations are being dealt with rather than
a library itself.
3. By seeing the behavior of each class it is found that the title of a book gives
information about the book. It is an attribute of the object book. Therefore title is not
a class.
The classes left with are
Book
Journal
Step two: Identify the semantics of the classes

The aim of identifying semantics of classes is to define the structure and the
behavior of the classes. The operations required to realize the behavior are added to the
class definition. It may be just the name of operation or its complete signature.
Example
Consider the class Book. The behavior of the Book is characterized by being
issuable, renewable and returnable. Three operations can be added to realize this behavior
to the class Book. Title can be defined as an attribute to the class Book.
The class Book is now defined as
Name :
Book
Operations:
Issue()
Return()
Renew()
Get_title()
Attributes:
Title
Next consider the class journal. The behavior of journal is characterized by two
operations- Issue and Return. The journal also has a title as in the case of a book. A
selector is added to retrieve its title. The class definition is given below.
Name:
Journal
Operations:
Issue(0
Return()
Get_title()
Attributes:
Title
Step three: Identify the relationship among the classes

Two kind of relationships where brought out – ‘is-a’ and ‘has-a’. In this step the
class definitions is looked to check if any of these can be defined.
Identify the common attributes and operations and define a superclass.
In the above example Books and Journals have common attributes and behavior.
Both can be issued out and returned. A class hierarchy in this case can be defined. The
common attribute is Title and common operations are Issue and Return. Both the classes
Book and Journal can inherit these properties from the class Item.The definition of the
classes and the corresponding hierarchy are as follows.
Name:
Item
Operations:
Issue()
Return(0
Get_title()
Attributes:
Title
Name:
Book
Super class:
Item
Operations:
Renew()
Name:
Journal
Super class:
Item

Item

Book Journal

In this design instance of only books and journals are created. Therefore class
Item is an abstract class.
Books can be borrowed for a month, but journals can be borrowed for only one
day. Assume that the implementations of issue (), stamps the return date. Then the
operation definition and the implementation for issue, is different for book and journal.
Thus the operation issue () is overridden in each of the subclasses.
The design alternations for the implementation of issue ()
1. The Item class defines the operation issue () for only one day. Then only the
class book would have to override the implementations. Then the definition of
the class journal and the class Item is not different. In this case Journal class can
be avoided and Item is no more an abstract class. The definition of the classes
and the corresponding hierarchy is given below.
Name:
Book
Operations:
Issue ()
Return ()
Get_title ()
Attributes:
Title
Name:
Book
Super class:
Item
Operations:
Renew ()

Item

Book

Step four: Specify the Inheritance and implementations of these classes.

This step identifies the details of the inside view. The representations of the
attributes and the algorithms for implementing the operations are detailed below.
• For each class develop precise signature for the operations
• Provide a suitable algorithm for each operation., optimize their implementations.
If a certain value is repeatedly computed, check if it should be stored as an
instance variable of the class.
• Add any instance variable to the structure of the class that may be required to
realize the behavior.
• Before implementing each class, see if inheritance can be defined to reuse some
property, which exists. Alter the inheritance hierarchy if necessary.
Consider the design alternate 1(a) of the previous step, the class Item is an
abstract class. The operations are issue () and return (). In order to define the signature of
the operation, these operations are to be analyzed further.
1. In case of issue (), Item can be marked as not available for issue any more. An
instance variable ‘available’ is added to the class ‘Item’ to represent this state of
the Item. The operation issue () will set the variable, and the operation return ()
will reset it.
2. Secondly the return date is to be stamped. An instance variable date is added to
store this information. A selector, which lets a person know when this is likely
to be returned, is added. The selector is get_date ().
3. Thirdly to keep of the borrower to whom the book is issued an instance
variable, borrower is added to this class. The borrower information must be
received as a parameter to the call. So the signature of issue is
Issue (borrower)
The type of the arrangement can be decided at this stage or at a later stage of the
design. When initial design is iterated.
4. Once borrower information is stored a selector can be defined to return this
information. The selector is defined as
Get_borrower ()
5. The remaining operation to be looked at is return (). When the book is returned
the Item becomes available and the variable available is reset. Any other
instance variable is not needed. The modified class Item is defined as follows
Name:
Item
Operations:
Issue (borrower)
Return ()
Get_title ()
Get_date ()
Get_borrower ()
Attributes:
Title
Available
Date
Borrower
The next class to be implemented is Book. The implementation of the operation
issue () is overridden in the class where in the instance variable date is assigned current
date + 30. The operation renew alters the return date of the book. Both operations do not
need any more instance variables to be added. The signature of renew () does not get
altered either
The class journal overrides the implementations of the operation issue (), by
assigning the date of next day to the variable date.
A design for the library operations is now ready. This design can be implemented
using C++.
MODULE-II

The C++ Class


Objectives:
 The Class
 Creating Objects
 Accessing Class Members
 Class Definition
Key Points
 C++
• C++ is an object oriented language.
• C++ has all the feature of the language C. In addition it permits the definition of
class, hierarchy of classes and other object oriented features.
 The class
• A class is a way to bind the data and its associated functions together.
• When defining a class we defining a class we are creating a new abstract data
type that can be treated like any other built- in-data type.
Specifying a class
A class specification has two parts.
1. Class declaration
2. Class function definitions
Class declaration
• Describes the type and scope of its members.
General form of a class declaration is

class class_name
{
private:
variable declarations;
function declarations;
public:
variable declarations;
function declarations;
};
• Class declaration is similar to a struct declaration.
• The keyword class specifies that what follows is an abstract data of type
class_name.
• The body of a class is enclosed within braces and terminated by a semicolon.
• The class body contain the declaration of variables and functions.
• Keywords private and public are known as visibility labels.
Class members
• The functions and variables declared in a class are called class members.
• They are grouped under two sections.
1. Private- can be accessed only from within the class.
2. Public- can be accessed from outside the class also.
• The use of the keyword private is optional. By default the members of a class are
private.
Data members
• The variables declared inside the class are known as data members.
• Specify the attributes of the objects of the class.
• Define the name and type of the attributes.
Member functions
• The functions declared inside the class are member functions.
• Only member functions can have access to the private data members and private
functions.
• Define the interface of an object in a class.
Data hiding in classes

Private area

no entry to
Data
X
private area
Functions

Public area

Data

Entry allowed
Functions
To public area

• Data can hide from other classes using private declaration.


• Data hiding is the key features of object-oriented programming.
A simple class example
Class item
{
int number;
float cost;
public:
void getdata (int a, float b);
void putdata (void);
};
The function getdata () can be used to assign values to the member variables number and
cost and putdata () is displaying their values. These functions provide the only access to
the data members from outside the class. That means the data cannot be accessed by any
function that is not a member of the class item. Here the functions are declared, not
defined.
 Creating objects or instances
Once a class is defined there are two ways of creating the objects or instances of
this class.
1. By specifying a declaration list , as part of the class. That is by placing their names
immediately after the closing brace.
2. By creating variables of type using the class name.
Example:
1. Class item
{
int number;
float cost;
public:
void getdata (int a, float b);
void putdata (void);
}x,y,z;
2. item x,y,z;
• The above statements creates a variables x,y,z of type item.
• In C++ the class variables are known as objects.
• Declaration of an object is similar to that of a variable of any basuic type.
• The necessary memory space is allocated to an object at this stage.
• Class specification provides only a template ans does not create any memory
space for the objects.
 Accessing class members
• A member function of a class can be called only by an object of that class
using a dot operator.
• Object-name.function-name(actual arguments);
Example:
x.getdata (100, 75.5);
It assigns the value 100 to number and 75.5 to cost of the object x by implementing
getdata () function. The assignments occur in the actual function.
x.putdata();
Would display the values of data members.
x.number =100; is illegal because the number (declared private) can be accessed through
a member function and not by the object directly.
• Objects communicate by sending and receiving messages through member
functions.
• A variable declared as public can be accessed by the objects directly.
Example:
Class xyz
{
int x;
int y;
public:
int z;
};
xyz p;
p.x =0; //illegal
p.z =10 //ok, z is public.
 Class definition
The data definitions has two parts.
1. The class head
2. Class body
Class head
Consists of the keyword class followed by the name of the class.
Class body
Consists of the data members and member function enclosed in parenthesis followed by
an optional list.
Defining member functions
Member functions can be defined in two places.
1. Outside the class definition.
2. Inside the class definition.
Outside the class definition
The deference between the member function and normal function definition is that the
member function name must be preceded with the class name and the scope resolution
operator :: . This helps in identifying the declaration for function being defined.
Example
The member functions getdata () and putdata () can be defined as follows.
void item :: getdata (int a, float b)
{
number = a;
cost = b;
}
void item :: putdata (void)
{
cout<<”number :”<<number;
cout<<” cost : “<<cost;
}
Inside the class definition
Another method of defining a member function is to replace the function declaration by
the actual function definition inside the class.
Example:
Class item
{
int number;
float cost;
public:
void getdata (int a, float b)
{
number = a;
cost = b;
}
void putdata (void)
{
cout<<number;
cout<<cost;
}
};
When a function is defined inside a class, it is treated as an inline function.
A C++ program with class
# include <iostream.h>
class item
{
int number;
int cost;
public:
void getdata (int a, float b);
void putdata(void)
{
cout<<”number:”<<number;
cout<<”\ncost:”<<cost;
}
};
void item :: getdata (int a, float b)
{
number = a;
cost = b;
}
int main()
{
item x;
x.getdata (100,299.5);
x.putdata();
item y;
y.getdata(200, 175.5);
y.putdata ();
return 0;
}
Nesting of member functions
a member function can be called by using its name inside another member function of the
same class. This is known as nesting if member functions.
Example:
# include <iostream.h>
class set
{
int m,n;
public:
void input (void);
void display (void)
int largest (void);
};
int set :: largest (void)
{
if(m>=n)
return m;
else
return n;
}
void set :: input (void)
{
cout<<”input values of m and n “;
cin>>m>>n;
}
void set :: display(void)
{
cout<< “largest value =”<<largest();
}
int main()
{
set a;
a.input ();
a.display ();
return 0;
}
Private member function accessing
Some situations may require certain functions to be hidden from the outside
calls. Tasks such as deleting an account in a customer file, or providing increment to an
employee are events of serious consequences and therefore the function handling such
tasks should have restricted access. We can place these functions in the private section.
A private member function can only be called another member function (public) .Even an
object cannot invoke a private function using the dot operator.
Example:
Class sample
{
int m;
void update (void);
void write ();
};
function read () can be called by the function update () to update the value of m.
void sample :: update (void)
{
read ();
}

Constructor and Destructor Functions

objectives:

• Automatic initialization of data members - constructors


• Constructor with one argument, multi arguments
• Using the constructor
• Destructor
• Default constructor and destructor

Since C++ supports the concept of user-defined classes and the subsequent
initiations of these classes, it is important that initialization of these instantiations be
performed so that the state of any object does not reflect “ garbage”. One of the principles
of C++ is that objects know how to initialize and cleanup after themselves. This
automatic initialization and clean up is accomplished by two member functions – the
constructor and the destructor.

5.1 Constructors

By definition, a constructor function of some class is a member function that


automatically gets executed whenever an instance of the class to which the constructor
belongs comes into existence. The execution of such a function guarantees that the
instance variables of the class will be initialized properly.

A constructor function is unique from all other functions in a class because it is


not called using some instance of the class, but is invoked whenever we create an object
of that class.

A constructor may be overloaded to accommodate many different forms of


initialization for instances of the class. i.e. for a single class many constructors can be
written with different argument lists .

Syntax rules for writing constructor functions

• Its name must be same as that of the class to which it belongs.


It is declared with no return type (not even void). However, it will implicitly return a
temporary copy of the instance itself that is being created.
• It cannot be declared static (a function which does not belong to a particular
instance), const( in which you can not make changes).
• It should have public or protected access within the class. Only in very rare
circumstances the programmers declare it in private section.

e.g.

class boxclass
{

public :
boxclass ( int x1, int y1, int x2, int y2);
void disp(void);
private :
int x1, y1;
int x2, y2 ;

};

boxclass::boxclass(int ax1,int ay1, int ax2, int ay2)


{
x1 = ax1 ;
y1 = ay1 ;
x2 = ax2 ;
y2 = ay2 ;
}

5.2.1 Using the Constructor

There are basically three ways of creating and initializing the object. The first way
to call the constructor is explicitly as :

boxclass bigbox = boxclass ( 1,1,25,79);

This statement creates an object with the name bigbox and initializes the data
members with the parameters passed to the constructor function. The above object can
also be created with an implicit call to the constructor :

boxclass bigbox(1,1,25,79);

Both the statements given above are equivalent. Yet, another way of creating and
initializing an object is by direct assignment of the data item to the object name. But, this
approach works if there is only one data item in the class. This is obvious because we
cannot assign more than one value at a time to a variable.
e.g.

class counter
{
public :
counter ( int c) // constructor.
{
count = c;
};

private :
int count;

};

we can now create an object as,

counter cnt = 0;

In the above example , object cnt is initialized by a value zero at the time of
declaration. This value is actually assigned to its data member count. This is the third
way to initialize an object’s data member. Thus, all the following statements to initialize
the objects of the class counter are equivalent:

counter c1(20);
counter c1 = counter(30);
counter c1= 10;

Once the constructor for a class has been declared and defined, the program
must use it. In other words, objects cannot be declaring without initializing
them. For instance, in the above example, an object of class counter has to
be declared and initialized in one of the three ways given above.
Uninitialized objects like :

counter cx,cy;

are not allowed.

However, sometimes the data members of an object may not require initialization.
May be they have to be accepted from the user later. C++ is not so rigid in its approach. It
has defined means of circumventing such a problem. The key to defining an uninitialized
object is to have a constructor with default arguments.
.g.
class counter
{
public :
counter ( int c = 0) // Constructor.
{
count = c;
};

private :
int count;

};

In the example above, if the actual argument is not given, then the value of the
formal variable c in the constructor defaults to zero. Thus, declaration of objects of this
class can be uninitialized as well.

counter c1(20);
counter c2 = counter(30);
counter c3 = 10;
counter c4,c5;

A constructor can be used to generate temporary instances as well , as given


below :

counter create( int cc)


{
return counter(c);
}

An array of objects can be initialized at the time of declaration. A constructor has


to be provided foe the same. The example given below uses the class employee to
illustrate this.

class employee
{
public :
employee(char *n, int a, double s);

private:
char name[40];
int age;
double salary;
};
employee :: employee (char *n , int a, double s)
{
strcpy( name, n );
age = a;
salary = s;
}

void main()
{
employee E[3] = { employee(“sanat”,25,9600),
employee(“sanket”,35,12600),
employee(“priya”,28,21600)
};

5.3. Destructors

A destructor function gets executed whenever an instance of the class to which it


belongs goes out of existence. The primary usage of a destructor function is to release
memory space that the instance currently has reserved.

Syntax rules for writing a destructor function

• Its name is the same as that of the class to which it belongs, except that the first
character of the name is the symbol tilde ( ~ ).
• It is declared with no return type ( not even void ) since it cannot ever return a
value.
• It cannot be static, const or volatile.
• It takes no input arguments , and therefore cannot be overloaded.
• It should have public access in class declaration.

Generally the destructor cannot be called explicitly (directly) from the program.
The compiler generates a class to destructor when the object expires. Class destructor is
normally used to clean up the mess from an object. Class destructors become extremely
necessary when class constructor use the new operator, otherwise it can be given as an
empty function. However, the destructor function may be called explicitly allowing you
to release the memory not required and allocate this memory to new resources, in
Borland C++ version 3.1.
5.4.The default Constructor and Destructor

If you fail to write a constructor and destructor function, the compiler


automatically supplies them for you. These functions have public access and essentially
do nothing useful. If you were to write these functions yourselves, this would look like:

class employee
{
public :
employee()
{
}

~employee();
{
}
};

5.5. A Constructive Example

Consider an example , to model a user-defined data type for strings. The object
simulates a character array ( string ) using a character pointer and an integer variable for
its actual size, which can be determined at its run-time. The object doesn’t use a character
array , since it may impose a limit on the number of characters that can be stored.

e.g.

# include <iostream.h >


# include < string.h>

class string
{
public :
string ( char *s);
~string();
void putstr();

private :
char *cptr;
int size;

};
void main(void)
{
string s1(“ Hello student \n”);
string s2 = “ Welcome to C++ \n”;
string s3 = string ( “ its fun \n”);

s1.putstr();
s2.putstr();
s3.putstr();
}
string::string(char *s)
{
size = strlen(s);
cptr = new char[size + 1];
strcpy(cptr,s);
}

string::~string()
{
delete cptr;
}

void string::putstr()
{
cout << cptr;
}

The class defined in the above example contains a character pointer, which
allocates memory at run–time, after determining the actual size required. This programme
demonstrates the use of class along with the constructor and destructor to create a user
defined data type String. The constructor function contains a default argument of null
character, which will be assigned to the variable cptr in the absence of an actual
parameter. The destructor uses the delete operator to release the memory allocated by the
constructor .

A class can contain data members as well as function members. A member


function is the only way to access the private section members of a class. For initializing
the data members of the class, we may write a function just like any other function. But
then, we have to invoke this function explicitly. C++ provides a special function called
constructor. This function is called automatically when we create an object. It contains
code to initialize the member variables using the formal parameters if they are passed via
objects. If we write such a function then we must pass parameters each time. To evade
this problem we can write many constructors to give some flexibility to create objects
with different parameter lists. We can also use default arguments in the constructor.

C++ also provides a special member function called destructor, which is called
automatically when an object expires as per the scope rules. Both constructor and
destructors do not have return types, not even void. The destructor cannot have any
parameters as well.
Exercises

1. Create a class called Time that has a separate data members for day, month and
year. A constructor should be used to initialize these members. Then write a
function to add these dates and store the result in a third object and display it.

2. WAP to add co-ordinates of the plane. The class contains x and y co-ordinates.
Create three objects. Use a constructor to pass one pair of co-ordinates and a
function to accept the second pair. Add these variables of two objects and store
the result in the third.

Copy Constructor
Objectives
 Definition
 Default Copy Constructor
 Defining Copy Constructor Explicitly
Key Points
 Definition
Copy constructor is a special constructor used to declare and initialize an object from
another object. Each data member is copied on to the data members of the new object.
The process of initializing object through a copy constructor is known as copy
initialization. A copy constructor takes a reference to an object of the same class as itself
as an argument.
Every class has two constructors, a default constructor and a copy constructor. These are
identified by their unique declarations.
X () ; // default constructor
X ( const X & ) ; // copy constructor
X is the class identifier.
The default constructor is called automatically whenever an object is declared.
Like this X a ;
Copy constructor is called automatically whenever an object is copied (duplicated).
Like this X b ( a ) ;
This statement define the object ‘b’ and at the same time initialize it to the values of ‘a’.
Another form of this statement is
X b=a;
Example
Consider a class ‘point’ having data members ‘x’ and ‘y’. ‘point pt2’ is initialized with
‘point pt1’. The data members ‘x’ and ‘y’ of pt2 have the values 2 and 3.
Class point
{
public :
int x;;
int y ;
};
void main ()
{
point pt1 ( 2, 3 );
point pt2 = pt1 ;
}
 Default Copy Constructor
The special constructor is referred to as the copy constructor and the one which is defined
automatically by the system is called default copy constructor.
The default copy constructor for a given class ‘X’ is defined as
X :: X ( const X &);
For the class ‘point’ the copy constructor would be
Point :: Point ( const Point & p )
{
x = p.x ;
y = p.y ;
}
Point ( const Point & p ) ,this was invoked with ‘pt1’ as the actual parameter. The copy
constructor was invoked for the instance ‘pt2’. Thus ‘x’ and ‘y’ on the left hand side refer
to those of ‘pt2’.
The default copy constructor will simply copy objects bit-by-bit. Thus any time an object
is to be initialized using another object of its class, the corresponding copy constructor is
invoked.
The copy constructor is called automatically whenever
An object is copied by means of an explicit initialization.
An object is passed by value to a function.
An object is returned by value from a function.

Point near ( Point p);


Void main()
{
Point p1 ( 2 , 3 );
Point p2 = near ( p1 );
}
‘near is a function which returns a point that is close to the point passed as parameter.
Parameter ‘p’ is passed by value. When the function is invoked with ‘Point p1’ the values
2 & 3 of ‘x’, ‘y’ are copied onto the local instance in function ‘near’ using the copy
constructor.
Note that the copy constructor takes one parameter, the object that is going to copy. That
object is passed by constant reference because it should not be changed.
When copy constructor is called, it copies the complete state of an existing object into a
new object of the same class. If the class definition does not explicitly include a copy
constructor, then the system automatically creates one by default.
Example :
Class ratio
{
int num , den ;
public :
ratio ( int n=0 , int d=1)
{
num = n ;
den = d ;
}
void print ()
{
cout << num << ‘/’ << den ;
}
};
main ()
{
ratio x ( 100 , 360 );
ratio y ( x ) ;
cout << “ x = “ ;
x . print () ;

cout << “ y = “ ;
y . print () ;
}
x = 5/18 , y = 5/18
 Defining Copy Constructor Explicitly
When the data member is a pointer the default Copy Constructor may not be good
enough. The problem occurring with pointer data member can be explained with the
following example.
Class book
{
float accno ;
char * title ;
public :
book ( float , char * ) ;
~ book () ;
};
book :: book (float acno , char * t )
{
accno = acno ;
title = new char [ strlen ( t ) ];
strcpy ( title , t );
}
book :: ~ book ()
{
delete title ;
}
An instance of ‘book’ with accession number 1.64 and ‘title’ ‘C++’ is defined as follows.
Book fstcpy ( 1.64 , “C++” ) ;
In this case the constructor is invoked. The object layout for the instance ‘fstcpy’ is
shown below

Accno 1.64 ‘C’’+’’+’


title

The statement book seccpy = fstcpy ;


Invoke a copy constructor for initializing seccpy. The default copy constructor initializres
‘seccpy’ with the same accession number and title as ‘fstcpy’. Since ‘title’ is a pointer to
a string only the pointer value is copied. That is two objects point to the same memory
location.
Accno 1.64
title
Book fstcpy
‘C’’+’’+’

Accno 1.64
title
Book seccpy

The above object layout will not cause any problem, as far as accessing the data member
is concerned. But there is a potential danger when the destructor is invoked. The
destructor is invoked for every object that is created, when the object goes out of scope.
In the above example destructor is invoked for ‘fstcpy’ as well as for ‘seccpy’. The
following situation can occur when a destructor is invoked.
1) When the destructor is invoked, for one of the objects say ‘fstcpy’ it deletes the space
occupied by ‘title’,then the other object ‘seccpy’ has a reference to something which does
not exist.
2) Later it may happen that the space which ‘title’ points to in ‘seccpy’ is invoked, it
deletes what belongs to some other object.
The solution to this problem is that define a copy constructor explicitly. This function is
invoked for all cases, when a default copy constructor would be used.
Copy constructor defined explicitly for ‘book’ is given below.
Book : book ( const book & b )
{
accno = b.accno ;
len = b.len ;
title = new char [len + 1] ;
strcpy (title , b. title ) ;
}
space for holding the title of the ‘book’ is acquired in the copy constructor and the string
is copied into this space. Thus the data member ‘title’ in ‘fstcpy’ as well as ‘seccpy’ point
to different memory is deleted on the destructor of either object.
Questions
1. What is a copy constructor? How it is different from constructor?
2. Explain the applications of copy constructor with example.
The Dot Operator
The member function defined in the class can be invoked for instance of the class. This is
achieved by using the dot operator.
Example
Class book has an instance ‘b’. the data member ‘title’ can be accessed with the
statement.
b.title;
The ‘this’ Pointer
“this” pointer is a pointer to an object of extra ordinary capability. It points to the object
itself. Using “this” any member function can find out the address of an object.
The ‘this’ pointer is a special pointer that exists for a class. It is a pointer of the type of
class and points to an object of the class, when a member function is invoked. Every
reference to a data member is implicitly prefixed with this->. It is an implicitly declared
pointer to an object. You cannot declare the ‘this’ pointer or make assignments to it. The
type of the ‘this’ pointer for a member function of a class type X is X *const.
When several instances of a class come into existence, it naturally follows that
each instance has its own copy of member variables. If this were not the case, then for
obvious reasons it would be impossible to create more than one instance of the class. On
the other hand, even though the class member functions are encapsulated with the data
members inside the class definition, it would be very inefficient in terms of memory
usage to replicate all these member functions and store the code for them within each
instance. Consequently, only one copy of each member function per class is stored in
memory, and must be shared by all of the instances of the class.

But this poses a big problem for the compiler: How can any given member
function of a class knows which instance it is supposed to be working on ? In other
words, up to now in a class member function you have simply been referring to the
members directly without regard to the fact that when the instantiations occur each data
member will have a different memory address. In other words, all the compiler knows is
the offset of each data member from the start of the class.

The solution to this dilemma is that, in point of fact, each member function does
have access to a pointer variable that points to the instance being manipulated.
Fortunately this pointer is supplied to each member function automatically when the
function is called, so that this burden is not placed upon the programmer.
This pointer variable has a special name ‘this’ (reserved word). Even though the
this pointer is implicitly declared, you always have access to it and may use the variable
name anywhere you seem appropriate.

e.g.

class try_this
{
public :
void print();
try_this add(int);

private :
int ivar;

};

void print()
{
cout << ivar;
cout << this -> ivar ;
}

The function print refers to the member variable ivar directly. Also, an explicit
reference is made using the this pointer. This special pointer is generally used to return
the object, which invoked the member function. For example,

void main()
{
try_this t1,t2;

t2 = t1.add(3);
t2.print();
}

try_this try_this :: add(int v)


{
ivar = ivar + v;
return ( *this);
}

In the above example if ivar for t1 is 10 and value in


v is 2, then the function add() adds them and ivar for t1 becomes 12 . We want to store
this in another object t2, which can be done by returning the object t1 using *this to t2.
The result of t2.print() now will be 12.
Dereferencing the Pointer this

Sometimes a member function needs to make a copy of the invoking instance so


that it can modify the copy without affecting the original instance. This can be done as
follows :

try_this temp(*this);
try_this temp = *this ;

In OOP emphasis is on how the program represents data. It is a design concept


with less emphasis on operational aspects of the program. The primary concepts of OOP
is implemented using class and objects. A class contains data members as well as
function members. The access specifiers control the access of data members. Only the
public members of the class can access the data members declared in private section.
Once class has been defined, many objects of that class can be declared. Data members of
different objects of the same class occupy different memory area but function members
of different objects of the same class share the same set of functions. This is possible
because of the internal pointer ‘*this’ which keeps track of which function is invoked by
which object.

Pointers
Objectives
 Introduction to pointer variables
 Use of pointer variables
 The ‘new’ operator
Key points
 Introduction to pointer variables
• Definition
 A pointer is a variable that holds an address of a memory location.
 The content is what is stored within a memory location.
 Its address is a label that identifies its location.
Example
# include <iostream.h>
{
int loc1 = 37, int loc2 = 73 ;
cout << “ loc1 contains : “ << loc1 ;
cout << “ \nloc2 contains : “ << loc2 ;
cout << “ \n address of loc1 : “ << &loc1 ;
cout << “ \n address of loc2 : “ << &loc2 ;
‘ & ‘ is called the address operator.
Simply using the variable name indicates the contents of the memory location.
When the operator & is prefixed to a variable, the address of the variable is implied.
 Use of pointer variable
# include < iostream.h >
void main ()
{
int * ptr ;
int loc1 = 37 ;
int loc2 = 73 ;
ptr = & loc1 ;
cout << “ loc1 contains : “ << *ptr << “ in address : “ << ptr ;
ptr = & loc2 ;
cout << “ loc2 contains : “ << loc2 << “ in address : “ << ptr ;
}
* implies ‘ pointer to ‘.

 The ‘ new’ Operator


When a pointer is declared like this
float * p ;
It only allocates memory for the pointer itself. The value of the pointer will be some
memory address, but the memory at that address is not yet allocated. Any attempt to
allocate memory to which it points will be an error.
That is * p = 3.1459 ; // error
A good way to avoid this problem is
float x = 3.1459 ;
float * p = & x ;
cout << * p ; //ok * p has been allocated.
In this case accessing * p is no problem because the memory needed to store was
automatically allocated when x was declared p points to the same allocated memory.
Another way to avoid the problem of a dangling pointer is to allocate memory explicitly
for the pointer itself. This is done with the ‘ new ‘ operator.
Float * q ;
q = new float ; // allocates storage for float.
* q = 3.1459; // * q has been allocated.
The first two of these lines can be combined their by initializing q as it is declared.
Float * q = new float ;
Note that using ‘ new ‘ operator to initialize q only initializes the pointer itself, not the
memory to which it points. It is possible to do both in the same statement.
Float * q = new float ( 3.1459 ) ;
Pointers
Objective
 Dynamic memory allocation
 Pass by pointers
 Pointers to array
 Pointer void
Key points
 Dynamic memory allocation
A string array has memory space allocated only at the time of execution. No memory
allocation is done at the time of declaration. This is called dynamic allocation of memory.
This can be done with the help of ‘ new ‘ operator.
• Dynamic array
An array name is really just a pointer that is allocated at compile time.
Float a[20] ; a[20] is a static array which is assigned a fixed sized memory that is a block
of 20 floats assigned at the compile time. But an array size can be assigned at the
execution time, which is called dynamic array.
Example
Float * p = new float [20] ;
We can use a non-constant pointer to postpone the allocation of memory until the
program is running. It is called runtime binding or dynamic binding.
 Passing by pointers
Arguments can be passed to a function by value, by reference or by pointer. Passing by
reference implies passing the address of a variable. This is same as passing of pointer.
• Passing by reference
Example
# < iostream.h >
void main ()
{
void convert (float & );
float amt = 123.45;
float dollors = amt ;
convert ( amt ) ;
cout << “ amount “ << dollors << ” converted to Rs is “ << amt ;
}
void convert ( float & a )
{
a * = 31.65 ;
}
output
amount 123.45 converted to Rs is 3907.19.
This program can be written by passing pointer
# include < iostream.h >
void main ()
{
void convert (float * ) ;
float amt = 123.45 ;
float dollors = amt ;
convert ( & amt ) ;
cout << “ amount $ “ << dollors << ” converted to Rs is “ << amt ;
}
void convert ( float * a )
{
*a * = 31.65 ;
}
output
amount $ 123.45 converted to Rs is 3907.19.
 pointers to array
# include < iostream.h >
void main ()
{
float array [] = { 12.34, 23.45, 34.56, 45.67, 56.78 } ;
float * ptr ;
ptr = array ; //ptr points to the starting address of array.
For ( int k = 0 ; k < 5 ; k++ )
Cout << “ array [ ‘ << k << “ ] = “ << * (ptr ++ ) ;
}
Output
array [0] = 12.34 ;
array [1] = 23.45 ;
array [2] = 34.56 ;
array [3] = 45.67 ;
array [4] = 56.78 ;

 Passing of array by pointer


Example
# include < iostream.h >
const int l = 4 ;
void main ()
{
void convert ( float * );
float indrs [l] = { 12.34, 23.45, 34.56, 45.67 } ;
convert (indrs) ;
for ( int k=0 ; k<l ; k++ )
Cout << “ indrs [ ‘ << k << “ ] = $ “ << indrs[k] ;
}
void convert ( float * ptr)
{
for ( int m=0 ; m<l ; m++ )
* ptr ++ * = 31.65 ;
}

Output
indrs[0] = $ 390.561 ;
indrs [1] = $ 742.1925 ;
indrs [2] = $ 1093.82 ;
indrs [3] = $ 1445.455 ;

 Pointer void
It is a general purpose pointer which can point to any location regardless of its target
type. Such a pointer is declared with keyword “ void “ preceding it.
Example
# include < iostream.h >
void main (0
{
void * ptr ;
int in = 27 ;
char ch = ‘a’ ;
float fl = 12.34 ;
ptr = & in ;
cout << “ integer “ << in << “ is in loc “ << ptr ;
ptr = & ch ;
cout << “ char “ << *ptr << “ is in loc “ << ptr ;
ptr = & fl ;
cout << “ float “ << fl << “ is in loc “ << ptr ;

}
Composite Class
Composition
Composition of a class refers to the use of one or more classes within the definition of
another class. Composition is also called containment or aggregation. When a data
member of the new class is an object of another class, the new class is a composite of the
other objects.
A composite object can be defined as one which consists of the other objects. A
composite class is one whose objects are composite objects.
Example:
1) Consider the class ‘circle’ as a composite object containing an instance of ‘point’
representing the ‘centre’ and ‘radius’ which is of type ‘float’. The class definition is
Class circle
{
float radius ;
point centre ;
};

2) class author
{
char * name ;
char * addresss ;
};

Class publisher
{
Private:
Char * name;
Char * address;

};

Class Book

{
private:
float acc_no;
char * title;
Author writer;
Publisher *printer;
};

Acc_no
Title

Name
Address
(Author)

Name
Address
(publisher)

Component- a pointer to an object

It is possible to implement containment of objects using pointer to objects. When the data
member is a pointer to an object, then the composite object points to these contained
objects.
Example

The class definition Book is altered below. The data members ‘writer ‘ and ‘printer’ are
now pointers to the class ‘Author’ and ‘publisher’ respectively.
Class Book
{
private:
float acc_no;
char * title;
Author * writer;
Publisher * printer;
};

Acc_no Instance of Author


Title
Name
writer address

printer Name
address

Instance of publisher

When defining component objects with pointer to objects as data members, the classes to
which the component objects belong must either be defined earlier or have a forward
declaration.
Class Author; // forward declaration
Class publisher; // forward declaration
Class Book
{
// use Author and publisher here
};
The forward declaration is permitted only incase the data member is a pointer. The
forward declaration is not permitted if the data members are objects themselves.
Constructor for composite object
When an object is a composite object, then the data members which are objects must be
initialized in the constructor of the composite object. The composite object may have
1. A default constructor. Because the default constructor is explicitly defined in the
component class or it is generated by the system.
2. A constructor which expects parameter.
3. Both a default constructor and a constructor with parameters. In the constructor
of the composite object, the following rules may apply.
a) If the component object class has no default constructor, then the
constructor with parameters must be explicitly invoked.
b) If there is default constructor in the component object class, the default
constructor may or may not be invoked explicitly. Whenever the
constructor for the component object is not invoked explicitly, the default
constructor for it is invoked by the system.
When the composite class has no constructor
A default constructor is generated by the system for this class. When the constructor is
executed, the default constructor of the component object are called as per rule(b).
Example
Consider a class ‘circle’. There is no constructor defined for this class.
Circle c;
The system generated default constructor is invoked for ‘c’ which in turn invokes the
default constructor for ‘center’.

When constructors are explicitly defined for the composite class

Example
Consider the class ‘circle’ with an object of class ‘point’ as a data member. The class
‘circle’ has three constructors as shown below. One is the default constructor the second
which has the radius as a parameter, and the third which has three parameter for
initializing the center and the radius.
Class circle
{

Float radius;
Point center;
Public:
Circle ();
Circle (int r);
Circle (int x, int y, int r);
Void print()
{
Center.print();
Cout<<” radius = “<<radius;
}
};
Default constructor for ‘circle’ is defined as
Circle :: Circle ()
{
Radius = 0;
}
The default constructor for ‘point’ would be invoked in this case for initializing ‘center’.
Second constructor of ‘circle’ assign the value of ‘radius’.
Circle :: Circle (int r)
{
Radius = r;
}

Even in the case, the default constructor of ‘point’ invoked for initializing ‘center’.
In the third constructor the parameter x and y must be used to initialize centre ie by
explicitly invoking the construction of the component object when a constructor for a
class is to invoke the construction for the component data members, then these are
specified as part of the member initialization list. The first tow parameters of the
construction of circle are passed as argument to the construction of point; this is achieved
by specifying: center (x, y) before the body of the construction circle. The construction is
the class point which has two argument of type floating is invoked.
Circle :: Circle (int x, int y, int r) : centre (x,y)
{
Radius = r;
}

More than one member constructor


Class Author
{
Private:
Char * name;
Char * address;
Public:
Author ( char * );
};

Class publisher
{
Private:
Char * name;
Char * address;
Public:
publisher ( char * );
};

Class Book
{
private:
float acc_no;
char * title;
Author writer;
Publisher *printer;
Public:
Book (float num , char * t , char * w , char * p );
~ Book ();
};
When an instance of Book is created, then the constructor for Book with four parameters
is invoked. The two are to be used to construct writer and printer respectively. That is
within the constructor of Book, the constructor for ‘Author’ and ‘publisher’ are to be
invoked to initialize ‘writer’ and ‘printer’. These constructors are specified in the
initialization list of the constructor of ‘Book’. The definition of the constructor for ‘Book’
is
Book :: Book ( float num , char * t , char * w , char * p) : printer (p) , writer (w)
{ }
If more than one constructor is being invoked, the constructor for the data members are
invoked before the constructor for the composite class, then order is according to the
order in which they are specified.
When the data members which represent the component objects are pointer to
objects
In this case the pointers can be assigned a value like any data member of built in type.
Example
Book :: Book ( float num , char * t , Author * w , publisher * p)
{
printer = p;
writer = w;
}
In the constructor, pointers are passed as parameters, these values are assigned to the data
members of ‘Book’ in the body of the constructor.
A second constructor can be
Book :: Book ( float num , char * t , char * w , char * p)
{
printer = new publisher(p) ;
writer = new Author(w);
}

Here strings are passed instead of pointers to objects. Therefore instances of Author and
publisher are to be created in the body of the constructor with new operator. At the time
of creation, the constructor with ‘char * ’ as parameters is invoked for both the classes.
The address of the newly created objects returned by the new operator, is then assigned to
the pointer data members, ‘writer’ and ‘printer’.
Destructor for composite object

The destructor for the composite object and its members are invoked in the reverse order
of declaration in which the constructors are invoked. The destructor for the composite
object first followed by those of the members. The destructors for the members are
invoked in the reverse order of declaration.
Example
When an object of class ‘Book’ is deleted, the destructor for ‘Book’ , ‘publisher’ and
‘Author’ are invoked in that order.
If the objects are created using the operator new in the constructor, then these would
have to be explicitly deleted in the destructor.
Book :: ~ Book ()
{
Delete writer;
Delete printer;
}
Access control for component object

The data members of a composite object, which are themselves objects or pointers to
objects are accessed as any other data members of a class. The data members within these
objects can have any access specification namely private, protected or public. If the
access right is private or protected for the data members of the component class these can
be access only through the member functions of the component objects.
Example
Class Author
{
Private:
Char * name;
Char * address;
Public:
Author ( char * );
};

Class publisher
{
Private:
Char * name;
Char * address;
Public:
publisher ( char * );
};

Class Book
{
private:
float acc_no;
char * title;
Author writer;
Publisher *printer;
Public:
Book (float num , char * t , char * w , char * p );
Char * get_writer ();
};
Char * Book :: get_writer ();
{
Return writer.name; // illegal
}
To achieve this a selector in the class ‘Author’ has to be included as
Class Author
{
Private:
Char * name;
Char * address;
Public:
// other definitions
Char * ret_name ()
{
Return name;
}

};
The above function can be used inget_writer () as follows.
Char * Book :: get_writer ();
{
Return writer.ret_name ();
}

Special Features of C++


Structures
Structure Definition
• A structure in C++ is a class which has the members public by default.
• The only significant difference between a C++ struct and a C++ class is with the
default access specifier assigned to the members
• In C a struct is a user defined data type. It just consists of the definition of the data
structures and no functions.

A structure is a derived data type. It is a combination of logically related data


items. Unlike arrays, which are a collection of like data types, structures can be made of
members of unlike data type. The data items in the structures generally belong to the
same entity , like information of an employee, players etc.

The general format of structure declaration is:

struct tag
{
type member1;
type member2;
type member3;
:
:
}variables;
We can omit the variable declaration in the structure declaration and define it
separately as follows :

struct tag variable;

In C++ we can omit struct and simply write :

tag variable;
e.g.

Structure definition.

struct account
{
int accnum;
char acctype;
char name[25];
float balance;
};

Structure declaration.

struct account oldcust; [or]


account newcust;

We can refer to the member variables of the structures by using a dot operator (.).

e.g.

newcust.balance = 100.0

cout << oldcust.name;

We can initialize the members as follows :

e.g.

account customer = { 100, ‘w’, ‘David’, 6500.00};

We cannot copy one structure variable into another. If this has to be done then we
have to do memberwise assignment.

We can also have nested structures as shown in the following example :

struct date
{
int dd, mm, yy;
};

struct account
{
int accnum;
char acctype;
char name[25];
float balance;
struct date d1;
};

Now if we have to access the members of date then we have to use the following
method.

account c1;

c1.d1.dd=21;

We can pass and return structures into functions . The whole structure will get
copies into formal variable .

We can also have array of structures. If we declare array to account structure it


will look like,

account a[10];

Every thing is same as that of a single element except that it requires subscript in
order to know which structure we are referring to.

We can also declare pointers to structures and to access member variables we


have to use the pointer operator -> instead of a dot operator.

account *aptr;

cout << aptr->name;

A structure can contain pointer itself as one of the variables ,also called self-
referential structures.

e.g.
struct info
{
int i,j,k;

info *next;
};

Unions

A union is a space saving class. A union is also like a structure , except that only
one variable in the union is stored in the allocated memory at a time. It is a collection of
mutually exclusive variables , which means all of its member variables share the same
physical storage and only one variable is defined at a time. The size of the union is equal
to the largest member variables. A union is defined as follows :

union tag
{
type memvar1;
type memvar2;
type memvar3;
:
:
};

A union variable of this data type can be declared as follows,

Union tag variable_name;

e.g.

union utag
{
int num;
char ch;
};

union tag filed;

The above union will have two bytes of storage allocated to it. The variable num
can be accessed as field.sum and ch is accessed as field.ch. At any time, only one of these
two variables, can be referred to. Any change made to one variable affects another.
Advantages of unions

Thus unions use memory efficiently by using the same memory to store all the
variables, which may be of different types, which exist at mutually exclusive times and
are to be used in the program only once.
This session covered advanced concepts of the language like pointers, arrays,
references, and relation between them . As can be seen pointers and references can be
used to return more than one value from the functions, to speed the processing and to use
memory more efficiently. The session also covered the concepts of structures and unions.
The structures or records are the basic elements of a database. When they are used with
pointers, arrays etc, complex database management can be realized. The unions are used
to store variables of different types that are required at
mutually exclusive times.
Nested Classes

Many a times, it becomes necessary to have a class contain properties of two


other classes. One way is to define a class within another – that is a class with member
classes also called nested classes. This has nothing to do with inheritance. Another way is
multiple inheritance , which will be discussed later.

e.g.

class Aclass
{

public :
Aclass(int pv)
{
private_variable_A = pv;
}
private :
int private_variable_A;

};

class Bclass
{
public :
Bclass(int bpv, int apv): Aobj(apv)
{
private_variable_B = bpv;
}
private :
int private_variable_B;
Aclass Aobj; // Declaring an object here.
};

As can be seen , the class Bclass contains an object Aobj in its private section as
one of its members. Also, it contains a constructor function with the same name , to
which the two variables passed are bpv and apv. The variable bpv is used to initialize the
private variable of Bclass.
However, the constructor contains something after the colon. The part after the
colon in the definition of a constructor is called as initialization section and the actual
body of the constructor is called as assignment section . Initialization section initializes
the base class members , whereas assignment section contains statements to initialize the
derived class members .

As seen earlier , in case of the derived classes, the name of the base class
constructor is written after colon in the initialization section. This base class constructor
is called before the constructor in the derived class. However, this example does not
contain a derived class. This is the example of the nested class . In this case, the name of
the object of the member class ‘Aclass’ is written after the colon. It tells the compiler to
initialize the Aobj data member of Bclass with the value in apv. It is exactly like
declaring an object of Aclass with the statement :

Aclass Aobj(apv);

The only change is that, it is written after the colon in the initialization section of
the Bclass constructor. Its assignment section contains code to initialize its own members.
The same constructor function can also be written as :

Bclass (int bovine apv):Aobj(apv),private_variable_B = bpv;

Uses of Nested class

\
MODULE III

Static Member

Objectives:

 Static Data Members


 Static Member Functions
Key points
 A data member of a class can be qualified as static using the keyword ‘static’.
 Properties of static member variables
• It is initialized to zero when the first object of its class is created. No other
initialization is permitted.
• Only one copy of that member is created for the entire class and is shared
by all the objects of that class, no matter how many objects are created.
• It is visible only within the class, but its life time is the entire program.
• A static data member is independent of the objects. In fact it can be
accessed even when there is no object created for the class. In such a case it
is necessary that the data member be qualified with the class name, while
accessing it.
For Example:
The static data member ‘rate’ in the class ‘Loans’ can be accessed as ‘Loans :: rate; ‘
• Since a static data member is common to all the instance of the class, it can
not be initialized in a constructor. It has to be initialized outside the class
definition.
float Loan::rate=2.5;
• The static data members must obey the access rules of private, protected and
public.
Example:
Class Loan
{
private:
float principal;
int time;
static float rate;
public:
Loan(float p,int t)
{
principal = p;
time = t;
}
float get_rate();
float comp_int();
void incr_rate(float);
};
float Loan::comp_int()
{
float interest;
interest = principal*time*rate/100;
return interest;
}
float Loan::get_rate()
{
return rate;
}
A static data member is preferred over a global variable for the following reasons.
• By defining the data member as static information hiding can be enforced.
The static data member can be declared in the private part of the class
definition which ensures that it is visible only within the object. This is not
possible with a global variable
• Since the static data member is within the scope of the class, the name will not
be in conflict with other global variables.
Example of Static Data Members.
# include<iostream.>
class item
{
static int count;
int number;
public:
void get_data(int a)
{
number = a;
count++;
}
void get_count(void)
{
cout<<”\ncount:”<<count;
}
};
int item::count; //definition of static data member.
Int main()
{
item a,b,c;
a.get_count();
b. get_count();
c. get_count();
a.get_data(100);
b .get_data(200);
c.get_data(300);
cout<<”\nafter reding data”;
a. get_count();
b. get_count();
c. get_count();
return 0;
}
output
count = 0
count = 0
count = 0
After reading data
count = 3
count = 3
count = 3

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. Since they are associated with the class known as class
variables.
 Sharing of a Static Data member

Object1 object2 object3


Number Number Number
100 200 300

count
3 (common to all three objects)

The static variable ‘count’ is initialized to zero when the objects are created. The count is
incremented whenever the data is read into an object. Since the data is read into objects
three times, the variable count is incremented three times. Because there is only one copy
of count shared by all the three objects, all the three output statements cause the value 3
to be displayed. Static variables are like non-inline member functions. While defining a
static variable, some initial value can also be assigned to the variable.
Example:
int item :: count = 10;
 Static Member Functions
Like static member variables, we can also have static member functions.
Static member function properties
• A static function can have access to only other static members (functions
or variables) declared in the same class.
• A static member function can be called using the class name (instead of its
objects)
Class_name :: function_name;
• A member function which accesses only the static members can be made
static.
For example:
The member functions incr_rate() and get_rate() defined in ‘Loan’ class access only the
static member rate. These functions therefore can be declared to be static.
Example
# include <iostream.h>
class test
{
int code;
static int count; //static member variable
public:
void set_code(void)
{
code = ++count;
}
void show_code(void)
{
cout<<”object number:”<<code;
}
static void show_count(void) //static member function
{
cout<<”count:”<<count;
}
};
int test :: count;
int main()
{
test t1,t2;
t1.set_code();
t2.set_code();
test :: show_cout(); //accessing static function
test t3;
t3.setcode();
test :: show_cout();
t1.show_code();
t2.show_code();
t3.show_code();
return 0;
}
output
count : 2
count : 3
object number : 1
object number : 2
object number : 3
The following function definition is illegal.
Static void show_count()
{
cout<<code; //code is not static.
}
There are two ways in which a static member function can be invoked.
1. In the first instance it can be invoked directly even if no object is ever created. in this
case the class scope operator has to be specified.
Example:
Loan :: incr_rate(0.5);
2. In the second instance it may also be invoked through an instance of the class or a
pointer to an instance like any member function.
Example:
Loan l1;
Cout<<l1.get_rate();
When static member function is invoked the implicit ‘this’ pointer does not point to an
object of the class. However ‘this’ pointer must points to an object if data member which
are not static are to be accessed. Therefore the static member functions access only static
data members.
Example:
The function comp_int() in the class ‘Loan’ cannot be made static, as it accesses
‘principal’ and ‘time’ which are not static.
Conclusion
A data member which is declared as static, is common to all the instance of the class. A
static data member is independent of the object of the class. It can be accessed even when
there is no object created for the class.
A member function which access only the static data members can be declared to be
static.
Questions
1. What is a static data member?
2. What is the usage of static data members?
3. What is a static member functions?
Friend Functions
Objectives

 Friend Function Definition


 Special Characteristics of Friend Functions
 When non-member functions are friends to a class.
 Member functions of one class as a friend of another class
 Friend class
 Friend function as bridge between classes.
Key points

 Definition
A friend function to a class is a non-member function which has access to the private
and protected members in addition to the public members of the class.
The friend of a class are declared in the concerned class. The function declaration
should be preceded by the keyword friend. The function is defined elsewhere in the
program like a normal function. The function definition does not use either the keyword
friend or the scope operator ::. A function can be declared as a friend in any number of
classes.

 Special characteristics of a friend function.


• It is not in the scope of the class to which it has been declared as friend.
• Since it is not in the scope of the class it cannot be called using the object
of that class.
• It can be invoked like a normal function without the help of any object.
• Unlike member functions, it cannot access the member names directly and
has to use an object name and dot membership operator with each member
name (eg A.x).
• It can be declared either in the public or in the private part of a class
without affecting its meaning.
• Usually it has the objects as arguments

 When non-member functions are friends to a class.

Example
# include <iostream.h>
class sample
{
int a;
int b;
public:
void set_value ()
{
a = 25;
b = 40;
}
friend float (sample s)
{
return float (s.a + s.b)/2.0;
}
int main()
{
sample X;
X.set_value ();
Cout <<” mean value = “ << mean (X);
return 0;
}
output
Mean value = 32.5
The friend function accesses the class variables ‘a’ and ‘b’ by using the dot operator and
the object passed to it. The function call mean (X) passes the object X by value to the
friend function.
 Member function of one class as friend of another class
Member functions of one class can be friend function of another class. In such cases they
are defined using the scope resolution operator which is shown as follows.
Class X
{
--------- ;
--------- ;
int fun1 () ;
--------- ;
};
class Y
{
-------- ;
-------- ;
friend int X :: fun1 () ;
};
The function fun1() is a member of class X and friend of class Y.
 Friend Class
We can also declare all the member functions of one class as the friend function of
another class. In such cases the class is called a friend class. This can be specified as
Class Z
{
--------- ;
friend class X ;
};
 Friend functions as bridge between the classes
A function friendly to two classes.
Example 1:
# include <iostream.h>
class ABC ; // forward declaration.
Class XYZ
{
int x;
public:
void set_value ( int i )
{
x=i;
}
friend void max ( XYZ , ABC );
};
class ABC
{
int a ;
public :
void set_value ( int i )
{
a=i;
}
friend void max ( XYZ , ABC );
};
void max ( XYZ m , ABC n )
{
if (m.x >= n.a )
cout << m.x ;
else
cout << n.a ;
}
int main ()
{
ABC abc ;
abc.set_value (10);
XYZ xyz ;
xyz.set_value (20);
max (xyz , abc);
return 0 ;
}
output
20
The function max () has arguments from both XYZ and ABC. When the function max ()
is declared as a friend in XYZ for the first time, the compiler will not acknowledge the
presence of ABC unless its name is declared in the beginning as
Class ABC ;
This is known as forward declaration.
Example 2:
Swapping private data of classes.
Class class_2 ;
Class class_1
{
int value1;
public :
void indata ( int a )
{
value1 = a ;
}
void display ( void )
{
cout << value1 ;
}
friend void exchange ( class_1 & , class_2 & ) ;
};
class class_2
{
int value2;
public:
void indata 9 int a )
{
value2 = a ;
}
void display ( void )
{
cout << value2 ;
}
friend void exchange ( class_1 & , class_2 & );
};
void exchange ( class_1 & x , class_2 & y )
{
int temp = x.value1 ;
x.value1 = y.value2 ;
y.value2 = temp ;
}
int main ()
{
class_1 c1 ;
class_2 c2 ;
c1.indata (100) ;
c2. indata (200 ) ;
cout << “ values before exchange “ ;
c1.display () ;
c2.display () ;
exchange ( c1, c2 ) ;
cout << “ values after exchange “ ;
c1.display () ;
c2.display () ;
return 0 ;
}
Output
Values before exchange
100
200
Values after exchange
200
100
Questions
1. What is a friend function? Explain the merits and demerits of using friend
function.

Pointers to Objects and members


Objectives
 Pointers to Objects
 Array of Pointers
 Pointers to Data Members
 Pointers to Member Functions
Key Points
 Pointers to Objects
Pointers can point to objects as well as to simple data types. Some times we don’t know
at the time that we write the program, how many objects we want to create. When this is
the case we can use ‘new ‘ operator to create objects while the program is running. That
is ‘new ‘operator can be used to allocate memory dynamically with creation of each
object of a class.
Example
Class currency
{
float amt ;
public :
void fetch ()
{
cout << “ \n Enter amount “;
cin >> amt ;
}
void display ()
{
cout << “ \n amount is : “ << amt;
}

};
void main ()
{
currency * ptr ;
ptr = new currency ; //ptr is returned as an address pointer when
//we allocate memory to the class currency
ptr -> fetch () ;
ptr -> display ();
}
 Array of Pointers
Creating an array of pointers to objects enables easy access to objects. This is an alternate
to setting up an array of objects.
Example
# include < iostream.h >
class country
{
char coun [20] ;
public :
void fetch ()
{
cout << “ Country Name : “ ;
cin >> coun ;
}
void show ()
{
cout << “ country is : “ << coun ;
}
};
void main ()
{
country * counptr [20] ;
int pt = 0 ;
char ne ;
do
{
counptr [pt] = new country ;
counptr [pt] -> fetch() ;
counptr [pt] -> show() ;
ptr ++ ;
cout << “ \n continue ? ( y/n ) : “ ;
cin >> ne ;
} while ( ne == ‘y’ ) ;
}

Derived class
How to define a derived class ?

A singly inherited derived class id defined by writing :

• The keyword class.


• The name of the derived class .
• A single colon (:).
• The type of derivation ( private , protected, or public ).
• The name of the base, or parent class.
• The remainder of the class definition.

e.g.

class A
{
public :
int public_A;
void public_function_A();

private :
int pri_A;
void private_function_A();

protected :
int protected_A;
void protected_function_A();

};

class B : private A
{
public :
int public_B;
void public_function_B();

private :
int pri_B;
void private_function_B();
};

class C : public A
{
public :
int public_C;
void public_function_C();

private :
int pri_C;
void private_function_C();

};

class D : protected A
{
public :
int public_D;
void public_function_D();
private :
int pri_D;
void private_function_D();

};

A derived class always contains all of the member members from its base class . you
cannot “subtract” anything from a base class. However, accessing the inherited variables
is a different matter. It is also important to understand the privileges that the derived class
has insofar as access to members of its base
class are concerned. In other words, just because you happen to derive a class
does not mean that you are automatically granted complete and unlimited access
privileges to the members of the base class. to understand this you must look at the
different types of derivation and the effect of each one.

Private derivation

If no specific derivation is listed, then a private derivation is assumed. If a new


class is derived privately from its parent class , then :

• The private members inherited from its base class are inaccessible to new member
functions in the derived class . this means that the creator of the base class has
absolute control over the accessibility of these members , and there is no way that
you can override this.
• The public members inherited from the base class have private access privilege.
In other words, they are treated as though they were declared as new private
members of the derived class, so that new member functions can access them.
However, if another private derivation occurs from this derived class, then these
members are inaccessible to new member functions.

e.g.

class base
{
private :
int number;
};

class derived : private base


{
public :
void f()
{
++number; // Private base member not
accessible
}
};

The compiler error message is

‘ base :: number ‘ is not accessible in the function derived :: f();


e.g.
class base
{
public :
int number;
};

class derived : private base


{
public :
void f()
{
++number; // Access to number O.K.
}
};

class derived2 : private derived


{
public :
void g()
{
++number; // Access to number is
prohibited.
}
};

The compiler error message is

‘ base :: number ‘ is not accessible in the function derived2 :: g();

Since public members of a base class are inherited as private in the derived class,
the function derived :: f() has no problem accessing it . however, when another class is
derived from the class derived , this new class inherits number but cannot access it. Of
course, if derived1::g() were to call upon derived::f(), there is no problem since
derived::f() is public and inherited into derived2 as private.

i.e. In derived2 we can write,

void g()
{
f();
}

or there is another way. Writing access declaration does this.

class base
{
public :
int number;
};

class derived : private base


{
public : base :: number ;

void f()
{
++number; // Access to number O.K.
}
};

class derived2 : private derived


{
public :
void g()
{
++number; // Access to number O.K
}
};

As you have just seen private derivations are very restrictive in terms of
accessibility of the base class members . therefore, this type of derivation is rarely used.

Public derivation

Public derivations are much more common than private derivations. In this
situation :

• The private members inherited from the base class are inaccessible to new
members functions in the derived class.
• The public members inherited from the base class may be accessed by new
members functions in the derived class and by instances of the derived class .

e.g.

class base
{
private :
int number;
};

class derived : public base


{
public :

void f()
{
++number; // Private base member not
accessible
}
};

The compiller error message is

‘ base :: number ‘ is not accessible in the function derived::f();


Here, only if the number is public then you can access it.

Note : However example 2 and 3 in the above section works here if you derive them as
“public”.

The Protected Access rights

In the preceding example, declaring the data member number as private is much
too restrictive because clearly new members function in the derived class need to gain
access to it and in order to perform some useful work.

To solve this dilemma, the C++ syntax provides another class access specification
called protected . here is how protected works :

• In a private derivation the protected members inherited from the base class have
private access privileges. Therefore, new member functions and friend of the
derived class may access them.
• In a public derivation the protected members inherited from the base class retain
their protected status. They may be accessed by new members function and
friends of the derived class .

In both situations the new members functions and friends of the derived class
have unrestricted access to protected members . however, as the instances of the derived
class are concerned, protected and private are one and the same, so that direct access id
always denied. Thus, you can see that the new category of protected provides a middle
ground between public and private by granting access to new function and friends of the
derived class while still blocking out access to non-derived class members and
friend functions .

class base
{
protected :
int number;
};

class derived : public base


{
public :
void f()
{
++number; // base member access O.K.
}
};

Protected derivation

In addition to doing private and public derivations, you may also do a protected
derivation. In this situation :

• The private members inherited from the base class are inaccessible to new
member functions in the derived class.
( this is exactly same as if a private or public derivation
has occurred.)
• The protected members inherited from the base class have protected access
privilege.
• The public members inherited from the base class have protected have protected
access.

Thus , the only difference between a public and a protected derivation is how the
public members of the parent class are inherited. It is unlikely that you will ever have
occasion to do this type of derivation.

Summary of access privileges

1. If the designer of the base class wants no one, not even a derived class to access a
member , then that member should be made private .
2. If the designer wants any derived class function to have access to it, then that
member must be protected.
3. if the designer wants to let everyone , including the instances, have access to that
member , then that member should be made public .

Summary of derivations

1. Regardless of the type of derivation, private members are inherited by the derived
class , but cannot be accessed by the new member function of the derived class ,
and certainly not by the instances of the derived class .
2. In a private derivation, the derived class inherits public and protected members as
private . a new members function can access these members, but instances of the
derived class may not. Also any members of subsequently derived classes may
not gain access to these members because of the first rule.
3. In public derivation, the derived class inherits public members as public , and
protected as protected . a new member function of the derived class may access
the public and protected members of the base class ,but instances of the derived
class may access only the public members.
4. In a protected derivation, the derived class inherits public and protected members
as protected .a new members function of the derived class may access the public
and protected members of the base class, both instances of the derived class may
access only the public members .

Table of Derivation and access specifiers

Derivation Type Base Class Member Access in Derived Class

Private (inaccessible )
Private Public Private
Protected Private

Private (inaccessible )
Public Public Public
Protected Protected

Private (inaccessible )
Protected Public Protected
Protected Protected

Using the Derived Class

An instance of a derived class has complete access to the public members of the
base class . assuming that the same name does not exist within the scope of the derived
class , the members from the base class will automatically be used. Because there is no
ambiguity involved in this situation, you do not need to use scope resolution operator to
refer to this base class member.

class base
{
public :
base(int n = 0)
{
number = n;
}
int get_number();

protected :
int number;

};

int base :: get_number()


{
return number;
}

class derived : public base


{

};

void main()
{
derived d;

// First checks class derived , then class base


cout << d.get_number();

// Goes directly to class base


cout<< d.base ::get_number();
}
Output:
0
0.

Using derived instances to access function members without the base class name
and scope resolution operator, the compiler resolves the address by checking :

• Does the member function have scope in the derived class ? if so, use it ; else
• Does the member have scope in the parent class ? if so, use it ; else
• Does the member have scope higher up in the hierarchy ? if so use it; else
• Does the member have accessible cope higher up in the hierarchy? If so use it;
else
• Does the member exist in the file scope ? if so use it ; else generate a compilation
error.

Inheritance is the most powerful use of class and is also, probably, the most
important concept of OOP. It is the mechanism using which reusability of code is
achieved. The facility to use the existing tested code reduces the time and cost of writing
it all over again. This session introduced the concept of inheritance. The next session
covers more suitable aspects of inheritance
Invoking Base Constructor
A derived class instance contains the data members of its base classes, in addition to the
data members defined in this class. In order to initialize the part which is inherited, the
base class constructors are invoked in the constructor of the derived class.
Example
Consider the class ‘Account’ of a bank. Let there be different kinds of account: savings
bank account, current account etc.’Account can be a base class from which savings bank
account is derived.
Class Account
{
protected:
int accno;
char * name;
float balance;
public:
Account(int no, char * uname, float am)
{
accno = no;
name = (char *) new char (strlen (uname));
strcpy (name, uname);
balance = am;
}
};
class SB_Account : public Account
{
float min_balance;
public:
SB_Account ( int no, char * uname, float am, float min);
};
The parameters required by the base class constructor and those required by the derived
class constructor from the argument list of the constructor of the derived classs.
The constructors of the base classes are specified as a member initialization list in the
constructor of the derived class. This can be done only in the definition and not in the
declaration of constructor.
The definition of the constructor of SB_Account is
SB_Account :: SB_Account (int no,char * uname, float am, float min) :
Account (no,uname,am)
{
min_balance = min;
}
If a base class has a default constructor, then it may be omitted from the member
initialization list. In all other cases the constructor of the base must be specified.
The order of invocation of cinstructors is
• First the base class constructors are invoked. The are invoked in the order of
declaration in the class head.
• This is followed by the data members which may be specified in the member
initialization list.
• Finally the body of the constructor of the class itself is executed.
Destructor for Derived Class
The destructor of the derived classes are invoked in the reverse order of constructor
invocation. That is the destructor of the derived class is invoked first, followed by
destructors of the base classes. The base classes are destroyed in the reverse order of their
declaration. This is recursively applied to the hierarchy of classes.

Example
Class Account
{
public:
//constructor etc.
~ Account ()
{
cout<<” the destructor of Account”;
delete name;
}
class SB_Account : public Account
{
public:
~ SB_Account()
{
cout<<”the destructor of SB_Account”;
}
};

class J_SB_Account : public SB_Account

{
public:
~ J_SB_Account()
{
cout<<”the destructor of J_SB_Account”;
delete name;
}
};
void main()
{
J_SB_Account mine (1, “MINE”, 500, “Your”);
}
When this function is exited , the following statements are displayed on the screen.
In the destructor of J_SB_Account
In the destructor of SB_Account
In the destructor of Account
Overriding members

If joint_ac is an instance of J_SB_Account


J_SB_Account joint_ac;
Then in the statement joint_ac.name will always refer to J_SB_Account :: name. in order
to refer to the name in the base class Account, one has to use the class scope operator as
Accont :: name;
Below the function print_ac () prints the account number, name of the holder and
balance.
Class Account
{
// ----------
Void print_ac ()
{
Cout << “ Accno = “<<accno;
Cout << “ \n Name = “<<name;
Cout << “ \nbalance = “<<balance;
}
};
The function print_ac () must be redefined in the class J_SB_Account so that the name of
the joint holder is also printed.
Void J_SB_Account :: print_ac ()
{
Account :: print_ac ();
Cout << “ \n Joint Name = “<<name;

}
Whenever print_ac () is called for the instance of J_SB_Account it always refer to the
one in this class. This is the reason why the class scope operator Account :: is needed to
invoke the base class function.

Copy constructor under derivation

When an object is initialized with another object then the copy constructor is invoked.
The derived object has parts of many base classes in it, in addition to the data members
defined in the derived class. The base parts are initialized by invoking the copy
constructor of the respective classes and the data members defined in the derived class
are initialized using the copy constructor of this class.
When the members are pointers, they are a source of problem to the copy constructors.
Unless the copy constructor is explicitly defined in the class there can be dangling
pointers or the storage pointed at by the pointers can get deleted more than once in the
destructor.
Example
Assume that a savings bank account can optionally have a joint holder class
J_SB_Account defined below as a derived class of SB_Account.
class J_SB_Account : public SB_Account

{
public:
J_SB_Account ( int no, char * uname, float am, float m, char * jname);

};
A derived class constructor is permitted to explicitly invoke only the immediate base
class SB_Account is specified in the initialization list of the constructor of
J_SB_Account.
J_SB_Account :: J_SB_Account (int no,char * uname, float am, float m, char * jname) :
SB_Account (no , uname , am , m)
{
name = (char *) new char strlen ( jname ) ;
strcpy ( name , jname ) ;
}
The instance ‘mine_too’ of ‘J_SB_Account’ is initialized using the instance ‘mine’. The
destructor of ‘J_SB_Account’ and ‘Account’ explicitly delete the space allotted for
‘name’ in the constructor. As aresult the data member ‘name’ in ‘mine_too’ points to
aspace which does not contain the ‘name’. the last statement in the function below prints
junks for the ‘name’ of the account holder and the joint account holder.
Void main ( )
{ J_SB_
Account mine ( 1 , “ MINE ” , 500 , “ YOUR “ ) ; J_SB_Account *
mineptr = & mine ; J_SB_Account mine_too =
mine ; Mine_too . print_ac ( ) ;
In order to avoid such situations, it is necessary to define the copy constructor explicitly.
Two situations arise when there is a hierarchy of classes.
1) The derived class has not explicitly defined the copy constructor but some of the base
classes have defined explicitly the copy constructor for their respective classes.
2) The derived class has defined copy constructor explicitly.
Case-I
When an object of the derived class is initialized with another, the base class members
are initialized first. The copy constructor are invoked according to the order of
declaration of the base classes in the derived class. The base classes which have defined
the copy constructor explicitly, the user defined copy constructor is invoked for
initializing that part of the derived object. Otherwise default copy constructor is invoked.
Lastly the default copy constructor of the derived class is invoked.
Example-copy constructor for ‘Account’
Account :: Account (const Account & a )
{
accno = a.accno ;
name = (char *) new char strlen ( a.name ) ;
strcpy ( name , a.name ) ;
balance = a.balance ;
}

The instance ‘mine_too’ has the ‘name’ of Account properly initialized because user
defined copy constructor in ‘Account’ is invoked ‘name’ of ‘J_SB_Account ‘ points to
the same location as the instance ‘mine’. The ‘mine_too.print () ‘ will print the following
Accno = 1
Name = MINE
Balance = 500
Name =

Case-II
When the copy constructor is defined in the derived class explicitly, it is the
responsibility of this copy constructor to initialize all the data members. The base class
constructors are not invoked in this case.
Example
The copy constructor of J_SB_Account is defined below. It explicitly invokes the copy
constructor of its base class ‘SB_Account’. The class SB_Account has not defined the
copy constructor explicitly but its base class Account has. Therefore the default copy
constructor of SB_Account and the user defined copy constructor of Account are
executed.
J_SB_Account :: J_SB_Account (const J_SB_Account & a) :
SB_Account (a)
{
name = (char *) new char strlen (a.name ) ;
strcpy ( name , a.name ) ;
}

Virtual Functions

The keyword virtual was earlier used to resolve ambiguity for a class derived
from two classes, both having a common ancestor. These classes are called virtual base
classes. This time it helps in implementing the idea of polymorphism with class
inheritance . The function of the base class can be declared with the keyword virtual.
The program with this change and its output is given below.

class Shape
{
public :

virtual void print()


{
cout << “ I am a Shape “ << endl;
}
};
class Triangle : public Shape
{
public :
void print()
{
cout << “ I am a Triangle “ << endl;
}
};

class Circle : public Shape


{
public :
void print()
{
cout << “ I am a Circle “ << endl;
}
};

void main()
{
Shape S;
Triangle T;
Circle C;
S.print();
T.print();
C.print();

Shape *ptr;

ptr = &S;
ptr -> print();

ptr = &T;
ptr -> print();

ptr = &C;
ptr -> print();
}

The output of the program is given below:

I am a Shape
I am a Triangle
I am a Circle
I am a Shape
I am a Triangle
I am a Circle

Now, the output of the derived classes are invoked correctly. When declared with
the keyword virtual , the compiler selects the function to be invoked, based upon the
contents of the pointer and not the type of the pointer. This facility can be very
effectively used when many such classes are derived from one base class . Member
functions of each of these can be ,then, invoked using a pointer to the base class .

Pure Virtual Functions

As discussed earlier, an abstract class is one, which is used just for deriving some
other classes. No object of this class is declared and used in the program. Similarly, there
are pure virtual functions which themselves won’t be used. Consider the above example
with some changes.
class Shape
{
public :
virtual void print() = 0; // Pure virtual
function

};

class Triangle : public Shape


{
public :
void print()
{
cout << “ I am a Triangle “ << endl;
}
};

class Circle : public Shape


{
public :
void print()
{
cout << “ I am a Circle “ << endl;
}
};
void main()
{
Shape S;
Triangle T;
Circle C;

Shape *ptr;

ptr = &T;
ptr -> print();

ptr = &C;
ptr -> print();
}

The output of the program is given below:

I am a Triangle
I am a Circle
It can be seen from the above example that , the print() function from the base class is
not invoked at all . even though the function is not necessary, it cannot be avoided,
because , the pointer of the class Shape must point to its members.

Virtual Base Classes

This ambiguity can be resolved if the class derived contains only one copy of the
class base. This can be done by making the base class a virtual class. This keyword
makes the two classes share a single copy of their base class . It can be done as follows :

class base
{
:
:
};

class Aclass : virtual public base


{
:
:
};

class Bclass : virtual public base


{
:
:
};

class derived : public Aclass, public Bclass


{
:
:
};

This will resolve the ambiguity involved.

Object oriented programming has altered the program design process. Exciting
OOP concepts like polymorphism have given a big boost to all this. Inheritance has
further enhanced the language. This session has covered some of the finer aspects of
inheritance. The next session will resolve some finer aspects of the language.

Exercises:

1. Create a class drugs containing encapsulated data for medicine name, whether
solid or liquid, price and purpose of use. From this class derive two classes,
Ayurvedic and Allopathic. The class Ayurvedic should additionally store data
on the herbs used, association to be used (whether honey or water). The class
Allopathic should additionally include data on the chemicals used and the
weight in milligrams. The classes should contain constructors and destructors.
They should contain functions to accept data and display the data. The main()
should test the derived classes.
MODULE IV
Operator Overloading

Objectives:

• Introduction to Operator Overloading.


• Operator Overloading Fundamentals.
• Implementing the operator functions.
• Rules for overloading the operators.

All computer languages have built in types like integers, real numbers, characters
and so on. Some languages allow us to create our own data types like dates, complex
numbers, co-ordinates of a point. Operations like addition, comparisons can be done only
on basic data types and not on derived (user-defined) data types. If we want to operate on
them we must write functions like compare (), add ().

e.g.

if (compare (v1, v2) = = 0)


:
:

where v1 and v2 are variables of the new data type and compare () is a function that will
contain actual comparison instructions
for comparing their member variables. However, the concept of Operator Overloading, in
C++, allows a statement like

if (v1 = = v2)
:
:
where the operation of comparing them is defined in a member function and associated
with comparison operator(==).

The ability to create new data types, on which direct operations can be performed
is called as extensibility and the ability to associate an existing operator with a member
function and use it with the objects of its class, as its operands, is called as Operator
Overloading.

Operator Overloading is one form of Polymorphism ,an important feature of


object-oriented programming .Polymorphism means one thing having many forms, i.e.
here an operator can be overloaded to perform different operations on different data types
on different contexts. Operator Overloading is also called operational polymorphism.
Another form of polymorphism is function overloading.

Operator Overloading Fundamentals

The C language uses the concept of Operator Overloading


discreetly. The asterisk (*) is used as multiplication operator as well as indirection
(pointer) operator. The ampersand (&) is used as address operator and also as the bitwise
logical ‘AND’ operator. The compiler decides what operation is to be performed by the
context in which the operator is used.

Thus, the C language has been using Operator Overloading internally. Now, C++
has made this facility public. C++ can overload existing operators with some other
operations. If the operator is not used in the context as defined by the language, then the
overloaded operation, if defined will be carried out.
For example, in the statement

x = y + z;

If x, y and z are integer variables, then the compiler knows the operation to be
performed. But, if they are objects of some class, then the compiler will carry out the
instructions, which will be written for that operator in the class.
Operator Functions
Operators which are to be overloaded are are defined as operator functios. They are
declared like ordinary functions except that operator is introduced by specifying the
keyword operator. This is followed by the operator itself. The type of the result is
specified as the return type of the function and the operands form the argument list.
The general format of the Operator function is:

return_type operator op ( argument list );

Where op is the symbol for the operator being overloaded. Op has to be a valid C++
operator, a new symbol cannot be used.
Implementing Operator Functions

e.g.

Let us consider an example where we overload


unary arithmetic operator ‘++’.

class Counter
{
public :
Counter();
void operator++(void);
private :
int Count;

};

Counter::Counter()
{
Count = 0;
}

void Counter::operator++(void)
{
++ Count ;
}

void main()
{
Counter c1;

c1++; // increments Count to 1


++c1; // increments Count to 2
}

In main() the increment operator is applied to a specific object. The function itself
does not take any arguments. It increments the data member Count. Similarly, to
decrement the Counter object can also be coded in the class definition as:

void operator--(void)
{
-- Count ;
}
and invoked with the statement
--c1; or c1--;

In the above example , the compiler checks if the operator is overloaded and if an
operator function is found in the class description of the object, then the statement to
increment gets converted, by the compiler, to the following:

c1.operator++();

This is just like a normal function call qualified by the object’s name. It has some
special characters ( ++) in it. Once this conversion takes place, the compiler treats it just
like any other member function from the class. Hence, it can be seen that such a facility is
not a very big overhead on the compiler.

However, the operator function in the above example has a potential glitch. On
overloading , it does not work exactly like it does for the basic data types. With the
increment and decrement operators overloaded, the operator function is executed first,
regardless of whether the operator is postfix or prefix.

If we want to assign values to another object in main() we have to return values to


the calling function.

Counter Counter :: operator++(void)


{
Counter temp;

temp.Count = ++ Count ;
return ( temp );
}

void main()
{
Counter c1,c2;

c1 = c2 ++; //increments to 1, then assigns.


}

In this example , the operator function creates a new object temp of the class
Counter, assigns the incremented value of Count to the data member of temp and returns
the new object. This object is returned to main(). We can do this in another way by
creating a nameless temporary object and return it.

class Counter
{
public :
Counter(); // CONSTRUCTOR WITHOUT ARGUMENTS
Counter( int c); // CONSTRUCTOR WITH 1 ARGUMENT
Counter operator++(void);
private :
int Count;

};

Counter::Counter() // CONSTRUCTOR WITHOUT ARGUMENTS


{
Count = 0;
}

Counter::Counter( int c) // CONSTRUCTOR WITH 1 ARGUMENT


{
Count = c;
}

Counter Counter::operator++(void)
{
++ Count ;
return Counter(Count);
}

One change we can see is a constructor with one argument. No new temporary
object is explicitly created. However return statement creates an unnamed temporary
object of the class Counter initializes it with the value in Count and returns the newly
created object. Hence one argument constructor is required.

Yet another way of returning an object from the member function is by using the
this pointer. This special pointer points to the object, which invokes the function. The
constructor with one argument is not required in this approach.

Counter Counter :: operator++(void)


{
++ Count ;
return ( * this);
}

Rules for overloading an operator

This summarizes the most important points you need to know in order to do
operator function overloading.
• The only operators you may overload are the ones from the C++ list and
not all of those are available. You cannot arbitrarily choose a new symbol
(such as @) and attempt to “overload it.
• Start by declaring a function in the normal function fashion, but for the
function name use the expression:
Operator op
Where op is the operator to be overloaded. You may leave
one or more spaces before op.
• The pre-defined precedence rules cannot be changed. i.e. you cannot, for
example, make binary ‘+’ have higher precedence than binary ‘*’. In addition,
you cannot change the associativity of the operators.
• The unary operators that you may overload are:
-> indirect member
! not
& address
* dereference
+ plus
- minus
++ prefix increment
++ postfix increment (possible in AT & T
version 2.1)
-- postfix decrement
-- prefix decrement (possible in AT & T
version 2.1)
~ one’s complement

• The binary operators that you may overload are:


(), [], new, delete, *, / , %, + , - , <<,>>,
<, <=, >, >=, ==,! =, &, ^, |, &&, ||, =, *=, /=, %=,
+=, -, =, <<=, >>=, &=,! =, ^=, ','(Comma).
• The operators that can not be overloaded are:
. direct member
.* direct pointer to member
:: scope resolution
?: ternary
• No default arguments are allowed in overloaded
operator functions.
• As with the predefined operators, an overloaded
operator may be unary or binary. If it is normally unary,
then it cannot be defined to be binary and vice versa.
However, if an operator can be both unary and binary,
then it can be overloaded either way or both.
• The operator function for a class may be either a non-
static member or global friend function. A non-static
member function automatically has one argument implicitly
defined, namely the address of the invoking instance (as
specified by the pointer variable this). Since a friend
function has no this pointer, it needs to have all its
arguments explicitly defined).
• At least one of the arguments to the overloaded
function explicit or implicit must be an instance of the
class to which the operator belongs.
• We cannot use friend function to overload certain
operators. However memger functions can be used to
overload them.
The operators that can not use friend functions to
overloaded are:
= Assignment operator
() function call operator
[] subscripting operator
-> Class member access operator
• Binary arithmetic operator must explicitly return a value.

Arithmetic Operators
All programming languages provide the standard arithmetic
Operators +,-,* and / for numeric data types. So it is natural to
define for user defined numeric types like ‘Ratio’ class. In
older programming languages like ‘C’ this is done by defining
functions like this.
Rotio product (Ratio x,Ratio y)
{
Ratio Z (x.num*y.num,x.den*y.den);
Return Z;
}
Z = product (x,y);
C++ allows such functions to be defined using the standard
arithmetic operator symbols so that they can be called more
naturally.
Z = x*y;
In C++ the multiplication operator has a function name that uses
the reserved keyword operator: its name is “operator * “. Using
this in place of “product” in the code above.
Rotio operator * (Ratio x,Ratio y)
{
Ratio Z (x.num*y.num,x.den*y.den);
Return Z;
}

But this is not a member function. If it were we would have to


set it up onlt one argument.
Example-2
Consider a class COMPLEX for Complex numbers. It will have a real and an imaginary
member variable. Here we can see binary operator overloaded and also how to return
values from the functions.
class COMPLEX
{
int real, imaginary;
public:
//--------

};
consider defining the operator ‘+’ to operate upon complex numbers. The ‘+’ operarator
is overloaded to add two complex numbers.
1) The operator ‘+’ defined for the class complex as its member function is as shown
below.
class COMPLEX
{
public:
COMPLEX operator+(COMPLEX);

private:
int real, imaginary;
};

The operator ‘+’ is preceded by the keyword ‘operator’. When it is invoked one of the
operands is the object for which ‘+’ is invoked. Only the second operator is has to be
specified. The result is another object of the class ‘COMPLEX’.
In the function definition the real and imaginary parts of the two complex numbers are
first added. Then another complex number is created with the real and imaginary parts of
the result. The constructor assigns the result which is then returned as shown below.
COMPLEX COMPLEX :: operator+( COMPLEX b
{
return COMPLEX (real + b.real , imaginary + b.imaginary);
}
2) operator function as a non-member function
Suppose that C1, C2 and C3 are objects of this class. Symbolically addition can
be carried out as

C3 = C1 + C2;

The actual instructions of the operator are written in a special member function.

e.g.

COMPLEX COMPLEX :: operator+( COMPLEX C2)


{
COMPLEX temp;

temp.real = real + C2.real;


temp.imaginary = imaginary + C2. imaginary;
return (temp);
}

The above example shows how Operator Overloading is


implemented. It overloads “+” operator to perform addition on
objects of COMPLEX class. Here we have overloaded a binary
operator(+).
Consider an example, which depicts overloading of += (Compound
assignment), <, >, == (Equality),!=, + (Concatenation) using
String class.

class String
{
public :

String ();
String ( char str [] );
void putstr();
String operator + (String);
String operator += (String s2);
int operator < (String s2);
int operator > (String s2);
int operator == (String s2);
int operator != (String s2);
private :
char s[100];

};

String::String () // CONSTRUCTOR WITH


{
// NO ARGUMENTS
s[0] = 0;
};

String:: String( char str [] ) // CONSTRUCTOR WITH


{
// ONE ARGUMENT
strcpy(s,str)
};

void String:: putstr()// FUNCTION TO PRINT STRING


{
cout << s ;
};

String String :: operator+(String s2)


{
String temp;

strcpy(temp.s,s);
strcat(temp.s,s2.s);
return (temp);
}

String String :: operator+=(String s2)


{

strcat(s,s2.s);
return (*this);
}

int String::operator < (String s2)


{
return (strcmp (s, s2.s ) < 0);
}

int String::operator > (String s2)


{
return (strcmp (s, s2.s ) > 0);
}

int String::operator == (String s2)


{
return (strcmp (s, s2.s ) == 0);
}

int String::operator != (String s2)


{
return (strcmp (s, s2.s ) != 0);
}

void main()
{

String s1 = “welcome “;
String s2 = “ to the world of c++”;
String s3;

cout << endl << “s1 = “;


s1.putstr();

cout << endl << “s2 = “;


s2.putstr();

s3 = s1 + s2;
cout << endl << “ s3 = “;
s3.putstr();

String s4;

cout <<endl<<” *********************”;


s4 = s1 + = s2;

cout << endl << “ s4 = “;


s4.putstr();

String s5 = “ Azzzz “;
String s6 = “ Apple “;

if( s5 < s6 )
{
s5.putstr();
cout << ” < ”;
s6.putstr();
}
else if( s5 > s6 )
{
s5.putstr();
cout << ” > ”;
s6.putstr();
}
else if( s5 == s6 )
{
s5.putstr();
cout << ” = ”;
s6.putstr();
}
else if( s5 != s6 )
{
s5.putstr();
cout << ” < ”;
s6.putstr();
}
}

Output:

S1 = welcome
S2 = to the world of C++
S3 = welcome to the world of c++
**************************
S4 = welcome to the world of c++
Logical Operator
The operator && can be defined for the class ‘complex’ as an
example of overloading logical operators. The operator is defined
as the logical ‘and’ operator for complex numbers. As a member
function, its declaration in the class ‘complex’ is
Class complex
{
…………..
int operator && (complex);
}
Operator function definition is
int complex :: operator && (complex b)
{
if (real && b.real) && (imag && b.imag))
return 1; //returns 1 if the real and imaginary
//parts of both complex numbers
are //non-zero.
else
return 0;
}
If the operator were to be defined as a non-member function, the
definition would be as follows:
int operator && (complex a, complex b)
{
if ((a.real && b.real) && (a.imag && b.imag))
return 1;
else
return 0;
}
Relational Operator
We define ‘==’ for the class ‘complex’ as an example of
overloading relational operators. The operator ‘==’ shall return
1, if the two complex numbers are equal, else return zero.
Class complex
{
……….
Public:
int operator == (complex);
};
int complex :: operator == (complex b)
{
if ((real == b.real) && (imag == b.imag))
return 1;
else
return 0
}
As a non-member function the definition would be:
int operator == (complex a, complex b)
{
if ((a.real == b.real) && (a.imag == b.imag))
return 1;
else
return 0
}
void main()
{
complex a (5,3);
complex b (2);
if (a == b)
cout << “complex numbers are equal”;
else
cout << “complex numbers are unequal”;
}

Operator []
Normally the subscript operator [] is used to index arrays. One
can define this operator for a class, so that it is possible to
use it for objects of this class.
Example:
Consider a class ‘point’ and a class ‘line’ consisting of two end
points. A subscript operator is overloaded for this class.
The class ‘point’ is defined as
Class point
{
float x;
float y;
public:
point () ; //default constructor
point (float x1 , float y1) ;
void print();
};
point :: point (float x1, float y1)
{
x = x1;
y = y1;
}
void point :: print ()
{
cout << “x = ” << x << “\t y = “ << y ;
}
class line
{
point endpts[2] ;
public :
line (int , int , int) ;
point & operator [] (int i) ;
};
In this case the parameter of the operator function are used to
index the points of a line. Depending on the index the first end
point or the second end point is returned.
The subscript operator function can be defined as
Point & line :: operator [] (int i)
{
if (i >= 0 && i <= 1)
return ( endpts[i]);
}
The return type for the operator function has been defined to be
a reference type to an instance of class ‘point’.
Void main()
{
//create a line with end points (1,1) and (2,2)
line l(1,1,2,2);
//extract each end-point using [] and then print it.
l[0].print() ;
l[1].print() ;
}
The constructor in the class ‘line’ is defined as
line ::line (int i1,int i2,int i3,int i4)
{
endpts[0] = point (i1,i2);
endpts[1] = point (i3,i4);
}
In the function l[0].print(), l[0] is a reference to an instance
of ‘print’ for which the function print() defined in the class
‘point’ is invoked.
Output
X = 1 y = 1
X = 2 y = 2
Operator ()
The function call operator can be overloaded, just as other
operators. Popular uses of operator () are as an iterator, a
substring operator and subscript operator.
Consider an example: as an iterator.
Whenever there is a collection of objects, odered (list) or
unodered (set) an operator function () can be defined, which
iterates over all the elements and returns the next element.
Example:
Consider an unordered collection of an integer set. In the class
‘Intset’ the iterator () returns the next element in the set
starting from the first upon each invocation. Inorder to do this
in the set is necessary which must be initializes to 0 in the
constructor.
Class Intset
{
int value[10] ;
//other declarations.
int index,size ;
public:
Intset (int);
int operator () () ;
};
Intset :: Intset (int m)
{
index = 0 ;
size = m ;
}
The call operator function can be defined as
int Intset :: operator () ()
{
if (index , size)
return value[index++] ;
else
return (index = 0);
}
The operator (0 returns the next element in the set for each
call. It returns 0 when there are no more elements in the set.
The index is also initialized to 0, so that it has the right
value for the next iteration. The function display() has been
recorded using the iterator. It prints all the elements of a set
of type Intset.
Void display ( Intset & s,int size)
{
int i = 0 ;
while (i < size)
{
cout << s () ;
I ++ ;
}
}
Assignment Operator =
For every class there is a system defined assignment operator
which permits copying one object to another. Like the default
constructor the copy constructor and the destructor, the
assignment operator is created automatically for every class that
is defined. But it can be defined explicitly in the class
definition.
Example:
Class ratio
{
int num,den;
public:
ratio (int n = 0,int d = 1);
ratio (const ratio & ) ;
void operator = (const ratio & ) ;
};
void ratio :: operator = (const ratio & r)
{
num = r.num ;
den = r.den ;
}
It simply copies the member data from the object ‘r’ to the
object that owns the call.
Void main()
{
ratio r1,r2,r3 ;
cin >> r1 ;
cin >> r2 ;
if (r1 = r2)
cout << “ both r1 and r2 are same”;
else
cout << “ r1 and r2 are not equal “;
}

Dereferencing Operator ->


When a pointer to an object of a class c1 is defined, the
operator ‘->’ is used for accessing members of this object. It is
possible to define another class ‘c2’ includes a data member,
which is a pointer to ‘c1’. In the class ‘c2’ the operator ‘->’
is overloaded in such a way that objects of ‘c2’ behave like
pointers to objects of ‘c1’.
Example:
Consider the class ‘Intset’ and another class ‘ptrset’ where the
data member ‘ps’ is a pointer to an object of class ‘Intset’.
Class ptrset
{
Intset *ps;
Public:
Ptrset (Intset &s)
{
ps = & s ;
}
Intset * operator -> ();
};
Intset * ptrset :: operator -> ()
{
if (ps == 0)
{
------ ;
}
----- ;
return ps ;
}
void main ()
{
Intset s1(5) ;
Ptrset p1 (s1) ;
int i ;
I = p1 -> is_empty () ;
Cout << I ;
}

Overloading the Extraction and Insertion Operators

Here, you can accept the input and output the results of the user-defined
variables or objects just like normal variables. Consider a class Complex that
consists of two system defined variables, both float to denote the real and
complex part of a complex number. In general cases to accept these member
variables, we need to write some function say getval() and invoke it using the
object of the class say Comobj.getval() and similar method would be required to
display them. Using operator overloading we can accept or display the user-
defined object just like a normal variable . i.e. by overloading the extraction
operator >> we can accept the complex object as,

cin >> comobj;

Similarly, by overloading the insertion operator we can display the member


variables of the object as,

cout << comobj;

just as if it were a basic data type. Consider the example:

class Complex
{
public:

friend istream &operator >>(istream &is, Complex &c2)


friend ostream& operator << (ostream &os, Complex &c2)

private:
float real, imaginary;

};

istream& operator >> (istream &is, Complex &c2)


{
cout << “ enter real and imaginary “ << endl;
is >> c2.real >> c2.imaginary;
return (is);
}

0stream& operator << (ostream &os, Complex &c2)


{
os << “ the complex number is “ <<endl;
os << c2.real << “+i”<< c2.imaginary;
return (os);
}

void main()
{
Complex c1,c2;

cin >> c1;


cout << c1;

cin >> c2;


cout << c2;
}

The operator functions have to be declared friends , since they have to


access the user class and the objects of istream and ostream classes that are
system defined. Since these operator functions are friend functions, the two
objects – cin and cout are passed as arguments, along with the objects of the
user-class. They return the istream and ostream objects so that the operator can
be chained. That is the above two input statements can also be written as,

cin >> c1 >> c2;


cout << c1 << c2;
MODULE –V
Templates
Generic Programming
Generic Programming is an approach where generic types are used as parameters so that
they work for variety of suitable data types and data structures.
Template is a new concept which enable us to define generic classes and functions and
thus provides support for generic programming.
A template can be used to create a family of classes/functions.
Example
A class template for an array would be enable us to create arrays of various data types
such as ‘int array’ and ‘float array’. Similarly we can define a template for a function say
‘mul ()’ that would help us create various versions of ‘mul()’ for multiplying int, float
and double type values.
A template can be considered as a kind of macro. When an object of a specific type is
defined for actual use, the template definition for that class is substituted with the
required data type. The templates are sometimes called parameterized classes or
functions.
Example
Consider the class ‘Intset’. The class was defined as a set of integers. If a set of ‘char’ is
needed then another class ‘charset’ has to be defined. The interface to both the classes is
identical. These classes do not differ in their functionality but only in the type of objects
they hold. It is possible to create generic classes with the data type as a parameter and use
this class to create a set of any data type instead of defining a new class every time.
Function Templates

Function templates provide you with the capability to


write a single function that is a skeleton, or template,
for a family of similar functions. A function template
defines a generic function.
In function overloading technique it relieves someone who
is using your functions from having to know about different
names for various functions that essentially do the same
task. Unfortunately, overloaded functions are not the
ultimate solution to the problem that is inherent when
writing functions that are similar in their behavior.
Consider the following example:

int max(int x, int y)


{
return ( x > y) ? x : y ;
}

float max(float x, float y)


{
return ( x > y) ? x : y ;
}

long max( long x, long y)


{
return ( x > y) ? x : y ;
}

char max(char x, char y)


{
return ( x > y) ? x : y ;
}

void main()
{
cout << max( 1,2) << endl;
cout << max( 4L,3L) << endl;
cout << max( 5.62,3.48) << endl;
cout << max(‘A’,’a’) << endl;
}

The output is :
2
4
5.62
a

Even though function overloading is used, the problem


with this example is that there is still too much
repetitious coding. In other words, each function is
essentially doing the same task. Now, instead of you having
to write many functions, it would be nice if were to write
only one function and can accommodate almost any type of
input argument.

How a Function Template solves this problem


A function template solves the problem by allowing you
to write just one function that serves as a skeleton, or,
template, for a family of functions whose tasks are all
similar.

This function template does not specify the actual


types of the arguments that the function accepts; instead ,
it uses a generic, or parameterized type, as a “ place
holder”, until you determine the specific types. The
process of invocation of these functions with actual
parameter types is called the template instantiation.

How to write a function template

A function template should be written at the start of


the program in the global area, or you may place it into a
header file. All function templates start with a template
declaration.

The syntax is :

• The C++ keyword template


• A left angle bracket ( < )
• A comma separates a list of generic types, each one. A
generic type consists of two parts

1. the keyword class ( this usage of class has


nothing to do with the key word class used to
create user-defined type.)
2. a variable that represents some generic type, and
will be used whenever this type needs to be
written in the function definition. Typically the
name T is used, but any valid C++ name will do.
• A right angle bracket ( > ).

e.g.

template < class T>


T max(char x, char y)
{
return ( x > y) ? x : y ;
}

void main()
{
cout << max( 1,2) << endl;
cout << max( 5.62,3.48) << endl;
cout << max(‘A’,’a’) << endl;
cout << max( 4,3) << endl;
}

The output is :
2
5.62
a
6

Each of first three max () function class causes a


template function to be instantiated, first with an int,
then with a double and then with a char. The last call
using two integers does not cause another instantiation to
occur because this call can use the instantiated function
that was generated as a result of the first class that also
uses two integers.

The template needs to have parameters, either a


template type representing a type or a template non-type
parameter representing a constant expression.

e.g.

template < class Hello, const int size >


Hello min ( const Hello ( & array)[size])
{
Hello min_val = array [0];

for(int i=1; i<size; ++i)


{
if( array[i] < min_val)

min_val = array[i];

}
return ( min_val);
}

where Hello can be built in or user defined type and size


is always constant and integer.
A template type specifier can be used for variable
declaration ( in the above example , it is used to declare
min_val), casts etc., just like normal variable.
Function template with multiple parameters

we can have more than one template parameter type in the same template .

e.g.

template < class T1, class T2, class T3>


T3 min (T1 a , T2 b);
Function with two generic types
# include <iostream.h>
# include <string>
template <class T1, class T2>
void display (T1 x,T2 y)
{
cout << x << “ “ <<< y << ;
}
int main()
{
display (1999,”EBG”);
display (12.34,1234);
return 0;
}
Template Function Overloading
We can even overload function templates.A template function may be overloaded
either by template functions or ordinary functions of its name. In such cases the
overloading is accomplished as follows.
1. Call an ordinary function that has an exact match.
2. Call a template function that could be created with an exact match.
3. Try normal overloading resolution to ordinary functions and call the one that
matches.
An error is generated if no match is found.

e.g.

template <class T>


T min ( T *, int);

template <class T>


T min ( T , int);

template <class T>


T min ( T , T);
Example
# include <iostream.h>
# include <string>
template <class T>
void display(T x)
{
cout << “template display:” << x ;
}
void display(int x)
{
cout << “explicit display:” << x ;
}
int main()
{
display(100);
display(12.34);
display(‘C’);
return 0;
}
output
explicit display:100
template display:12.34
template display:c
Member function templates
General format of member function template is
Template <class T>
Return-type class-name <T> :: function-name(arglist)
{
-------
}
Non-type template arguments
A template can have multiple arguments. It is also possible
to use non-type arguments.
Example
Template < class T,int size>
Class array
{
T a[size];
--------
};
array <int,10) a1;
array <float,5) a2;
array <char,20) a3;

Class Templates.

In addition to function templates, C++ also supports the concept of class


templates. By definition, a class template is a class definition that describes a family of
related classes. The philosophy is essentially the same as that of function templates,
i.e., the ability to create a class (or structure) that contains one or more types that are
generic, or parameterized. Class template is a parameterized type with the type as the
parameters.

A class template is defined in a manner similar to that


of a function template. You start by writing a template
declaration followed by the class definition:

e.g.

Template <class T>


class test
{
private : T item;

// data and functions


};
the keyword ‘template’ specifies that a template is being
declared. The keyword ‘class’ specifies that the identifier
to follow is a type parameter which can be a built in type
or a user defined type. ‘T’ is the type name. ‘T’ may be
substituted by any data type.
Template class instantiation
A class created from a class template is called a template
class. That is a class template is used to create a class
of particular type.
• The generation of a class from class definition is called template instantiation. We
can declare variables of this class as follows:

void main()
{
test<int> intobj;
test<double> doubleobj;
}

In the first instantiation the entire template types


i.e. variables of type T will be converted as integers. In
the second case they are converted as double variables.
Creating an instance of a parameterized class follows the
syntax of defining an instance of a non-class template.
The only difference is that the class name is followed by
the angular brackets and the type
Class-name <type> object-name (argument-list)
Example of class template
# include < iostream.h >
const size = 3 ;
template < class T >
class vector
{
T * v ;
Public:
Vector ()
{
v = new T [size];
for ( int i=0;i<size;i++)
v[i]=0;
}

vector (T * a)
{
for (int i=0;i<size;i++)
v[i]=a[i];
}
T operator * (vector &y)
{
T sum=0;
For (int i=0;i<size;i++)
Sum+=this->v[i]+y.v[i];
Return sum;
}
};
int main()
{
int x[3]={1,2,3};
int y[3]={4,5,6};
vector <int> v1;
vector <int> v2;
v1 = x;
v2 = y;
int R = v1*v2;
cout<”R = “ <<R
return 0;
}
output
R = 32
Class template with multiple parameters
Of course, you may have more than one parameterized type between the angle brackets.
They are declared as a comma separated list within the template specification.

Template < class T1, class T2, class T3>


class classname
{
-------
-------
};

Each parameter should be preceded with the keyword class.

Template < class T, U > // Error


Template < class T, class U> // O.K.

Example
Two generic data types in a class definition.
# include <iostream.h>
template <class T1,class T2>
class test
{
T1 a;
T2 b;
Public :
test (T1 x,T2 y)
{
a = x;
b = y;
}
void show()
{
cout<< a <<”and” << b;
}
};
int main()
{
test <float , int> test1 (1.23,123);
test < int,char> test2 (100,’w’);
test1.show();
test2.show();
return 0;
}
output
1.23 and 123
100 and w
Template class specialization
There are some type for which default member functions as defined in the class
template may not be good enough. It may be necessary to provide a specialized class
definition of the class template to handle the particular type.
Consider the class ‘array’ defined below
Template < class T >
Class array
{
T * data;
int n;
public:
array (int s)
{
data = new T(S);
n = s;
}
};
when we consider an array of strings (which are pointers
to characters) we are looking at two dimensional array of
characters. This definition cannot be got by instantiating
array <char *>. Therefore the class template array has to
be specialized for char *.
Class array <char *>
{
char * data[100];
int n;
public:
array <char *> (int s)
{
for (int i=0;i<s;i++)
data[i]=new char(s);
n = s;
}
};
This definition is used by the compiler in place of
instantiation of array for the type char *.
A specialized class template can be defined only after
the general class template is defined. Once defined each
member function of the general template class must be
redefined in the specialized template class. If only a few
of the member functions need a redefinition for a
particular type instead of defining a specialized template
class one can override these member function for the
particular type.
int max(array a)
{
T m = a[0];
for(int i=1;i<s;i++)
if (a[i]>m)
m = a[i];
return m;
}
This function can be invoked for any array of any type.
The function given below is first invoked for an array of
‘char’ and then ‘int’.
Void main()
{
int i;
array <char> c1(10);
for (i=0;i<5;i++)
cin >> c1[i];
char cc = max(c1);
cout << cc;
array <int> i1(5);
for (i=0;i<5;i++)
cin >> i1[i];
int jj = max(i1);
cout << jj;
}
template <class T> class array
{
T * data;
int n;
public:
array (int s);
int size ()
{
return n;
}
If only the constructor of the class array has to be
redefined for string type then it can be overridden as
follows.
Array <char *> :: array <char *> (int s)
{
for (int i=0;i<s;i++)
data[i] = new char (s);
n = s;
}
Each string array is constructed using the specialized
definition.
Template class static member
A class template can declare static members. The static
members are associated with each instantiation of the
template. To illustrate the use of static data members a
data member count can be added to the class stack which
keeps track of the number of instances of stack created
for each type.
Template <class T>
Class stack
{
private:
T * stptr;
int top,max;
public:
static int count;
stack (int m)
{
top = 0;max = m;
stptr = new T[max];
count++;
}
};
template <class T> int stach <T> :: count = 0;
With each instantiation of the class template, memory is
allocated for the static data members, and initialized.
There is one static data member for each such
instantiation. The static template data member comes into
existence only upon instantiation of the class. Therefore
ccessing the data member before instantiation of the class
results in an error.
Cout << stack <float> :: count ; //error
Example
Void main()
{
stack <int> sint(10) ;
stack <int> s2int(50) ;
stack <char *> schar(10) ;
cout <<”No. of int stacks = “
<< stack <int> :: count ;
cout <<”No. of char * stacks = “
<< stack <char *> :: count ;
}
output
no of int stacks = 2
no of char * stacks = 1
Template static member function
Static template member function can be called without
creating any object of the class.
The definition of static member function is illustrated by
defining a class template ‘reiopr’ in which the comparison
operator is a static member function. The definition of the
class is given below.
Template <class T>
Class relopr
{
public:
static int gtr (T & b)
{
return (a > b);
}
};
The function gtr() is used in the function max(), instead
of using the operator ‘<’.
Template <class T>
T max (array <T> & a)
{
int s = a.size();
T m = a[0];
For (int i=1;i<s;i++)
If (relopr <T> :: gtr(a[i],m))
M = a[i];
Return m;
}
The advantage of the above approach is that the code for
finding the maximum and comparison are separated.

In this session we have seen how a static variable and static function
combination can be used for variables, which are shared by all the objects
and hence can be given a single memory location and how objects are not
required to invoke them. We also learnt how to share our private details
with friends, which though should not be overused, but becomes extremely
necessary sometimes. Using the manipulators and iostream objects we can
enhance the way our output appears on the screen. Functions can
be made as inline functions if they are small. These are substituted in place
of function calls and are faster compared to calling and returning as
compared to normal functions. We also learnt how the shortcomings of
function overloading could be overcome using template functions.

• A non-type parameter represents a constant value.

Template < class T, const int buffer >


class classname;

• The functions of the template classes obey the rules of the function templates.

This session covered the subtle aspects of C++, which


could not be classified under any of the previous sessions.
We discussed about friend functions, which though are very
tempting, should not be overused. The concept of templates
gives another dimension to overloading and reusability. We
saw how friend functions along with operator overloading
can make the objects look like normal variables and thus
giving the language a more natural look. We also covered
how to enhance the output of the program.

Exercises:
1. Write am program to accept details of N students.
Generate the register number for them using the static
variable and static functions.

2. An airlines company recruits female candidates for the


post of airhostess. WAP to create a class named
CANDIATE . The class should contain the candidate’s
name, age, sex, weight, height and qualification.
Include a constructor and a destructor for this class.
Include a member function to accept the data and
display the data. Create a class named PERFECT to
accept the exact requirements in terms of age, weight,
height, and qualification from the company.

The following checks should be performed:

--sex and qualification should be same as that of


PERFECT.
Overload the = operator for this check.

--age ,weight and height should be less than or equal


to the PERFECT. Overload the operator <= for this
check.

Based on the return type of the above perform the


following operations.

- if the first condition is -ve, then display the


message ,"rejected".
- if the first condition is +ve but the second is
-ve , then display, "will be called later".

- if both the conditions are +ve ,the candidate is


called
for the first interview and display "called for the
first interview.

Você também pode gostar