Page 1
1
I. OBJECT ORIENTED PROGRAMMING
C++ is an Enhanced version of c Language which is developed by Bjarne Stroustrup
in 1980 in AT & T’s Bell Lab. C++ Inherits many features from C Language and it also some
more features and this makes C++ an OOP Language. C++ is used for making some code
which may used by another peoples for making their applications .C++ provides Reusability
of Code for Another user. C++ is also known as Object Oriented Language or Simply
OOP Language because it provides capability to either make stand alone program or either
makes a reusable code for another users.
Concepts of Object Orientation
Object oriented programming was developed because limitations were discovered in
earlier approaches to programming. The organizing principle of a program is referred
to as paradigm.
Programming paradigm is the way of thinking how the problem is to be approached
and how the instructions are to be organized to get the solution.
It is generally observed that most programmers work in one language and use only
one programming style.
There are many styles or paradigms for program writing such as monolithic
programming, procedural programming, structured programming, object oriented
programming etc.
Monolithic Programming
The languages such as assembly language and BASIC language support this kind of
programming. The programs written in these languages consist of only global data and
sequential code. Program flow control is achieved through the use of jumps and the program
code is duplicated each time it is to be used, since there is no support of the subroutine
concept and hence, it is suitable for developing small and simple applications.
Procedural Programming
Programs were considered as important interface between the problem and the
computer in the mid 19600s. Languages such as FORTRAN and COBOL support procedural
programming. The principle followed here is ‘decide which procedures you want and use
Page 2
2
the best algorithm you can find’. The focus is on doing things. That is, each statement in the
language tells the computer to do something as in: Get some input, add these numbers ,
divide by 6, display that output. A program in procedural language consists of a list of
instructions.
The following are the important features of procedural programming.
Programs are organized in the form of subroutines and all data items are global.
Program controls are through jumps and subroutine calls.
Subroutines are abstracted to avoid repetitions.
Suitable for medium sized software applications.
Difficult to maintain and enhance the program code.
Structured Programming
When programs became complex and large in size, a single list of instructions
becomes cumbersome. Hence the instructions were broken down into smaller units called
functions or sub programs in order to make programs more comprehensible to their human
creators. The related functions were grouped along with their data to form a module. Here the
data is kept hidden under modules and the programming paradigm follows the idea: ‘decide
which procedures you want, partition the program so that data is hidden in module’.
Dividing a program in to functions and modules is one of the cornerstones of structured
programming. Languages such as Pascal and C support structured programming.
The following are the important features of structured programming:
Emphasis is on algorithm rather than data.
Programs are divided into individual procedures that perform discrete tasks.
Procedures are independent of each other as far as possible.
Procedures have their own local data and processing logic.
Parameter passing between procedures facilitates information communication.
Controlled scope of data.
Page 3
3
Introduction of the concepts of user defined data types.
Support for modular programming.
Projects can be broken up in to modules and programmed independently.
Scope of data items is further controlled across modules.
A rich set of control structure is available to further abstract procedures.
Maintenance of a large software system is tedious and costly.
OBJECT ORIENTED PROGRAMMING
The following are important features of object oriented languages:
Improvement over the structured programming paradigm.
Emphasis on data rather than algorithm.
Data abstraction is introduced in addition to procedural abstraction.
Data and associated operations are unified into a single unit, thus the objects are
grouped with common attributes, operations and semantics.
Programs are designed around the data being operated, rather than the operations
themselves.
Decomposition is on data rather than procedure.
Relationships can be created between similar, yet distinct data types.
The advantage of OOP lies in its suitability in various applications. It is a well-suited
paradigm for the following.
Modeling the real - world problem as close as possible to the user’s point of view.
Interacting easily with computational environment using familiar descriptions.
Constructing reusable software components and easily extendable libraries.
Easily modifying and extending implementations of components without having to
recode everything from scratch.
Page 4
4
Structured V/s Object oriented Programming
Though structured programming and OOP are the popular paradigms today, there are
some significant differences between them. They are listed in the following table:
Structured Programming OOP
1. Stress is on the algorithms used
to solve the problem. Data takes
the back seat.
2. Algorithm for solving the
problem is compartmentalized in
to modules or functions.
3. Uses the best algorithm from
among the different procedures
available.
4. Adopts the divided and conquer
policy in a smaller region.
5. It has reduced data security and
data integrity, as they are
globally accessible to all the
functions.
1. Focus is given to the data
rather than the procedure.
2. Data is compartmentalized (or
encapsulated with associated
functions) in to capsules or
objects.
3. Decides the classes and
objects required and provides
full set of operations for each
class.
4. Adopts the divided and
conquer policy in a bigger
region.
5. It is centered on the concepts
of objects, data abstraction,
encapsulation, inheritance and
polymorphism.
Characteristics of OOP
i. Class
ii. Object
iii. Data Abstraction
iv. Encapsulation
v. Inheritance
vi. Polymorphism
vii. Modularity
Page 5
5
Objects
An object can be a person, a place, or a thing with which the computer must deal.
Objects mainly serve the following purposes:
Understanding of the real world and a practical base for designers.
Decomposition of a problem into objects depends on judgment and nature of
the problem.
Every object will have data structures called attributes and behavior called operations.
Classes
The objects with same (say, similar) data structure (attributes or character istics)
and operations (behaviour) are grouped into a class.
The following points on classes can be noted.
A class is a template that unites data and associated operations.
A class is an abstraction of the real world entities with similar properties.
A class identifies a set of similar objects.
Ideally, the class is an implementation of abstract data type.
Data Abstraction
Data abstraction refers to the act of representing essential features without including the
back ground details. It is the concept of simplifying a real world concept into its essential
elements.
Data Encapsulation
Encapsulation is a mechanism that associates the code and the data it manipulates and
keeps them safe from external interference and misuse.
Inheritance
Inheritance is the capability of one class of things to inherit properties from another class. It
allows the declaration and implementation of one class to be based on an existing class
The need for inheritance lies in its following advantages:
It is capable of expressing the inheritance relationship among the classes,
which makes it close to ensure the real world model. (See the figure 3.8)
Page 6
6
It facilitates the reusability of the code. The functions of a class can be used
for another class without modifying it. Also it can have additional functions.
The function defined in the class 'Students' to read data like student's name, date of
birth, address etc. is necessarily required for the derived classes, 'School Students'
and `IISS Students' and even for the 'LP Students' and 'Humanities Students'.
One of the additional functions in the derived classes of `11SS Students' may be
the function to read data related to the subject combinations.
Inheritance is transitive in nature. That is, if a class A inherits properties
from another class B, then all subclasses of A will automatically inherit the
properties of B. The function specified in the above point, that is, one
defined in the class 'Students' is inherited into the sub class 'IBS Students' and
the same may be derived into the class 'Commerce Students'.
Inheritance not only supports reuse across systems, but also directly facilitates
extensibility within a given system.
Polymorphism
Polymorphism is the ability for a message or data to be processed in more than one
form. It is the property by which the same message can be sent to objects of several
different classes. Polymorphism in C++ is achieved by the following and they will be
explained in later chapters.
Function Overloading
Operator Overloading
Dynamic Binding
Modularity
Modularity is the property of a system that has been decomposed into a set of
unified and loosely coupled modules. What we need is to assemble these modules in
the proper order. Likewise in programming, a problem is decomposed into smaller and
smaller modules so that each of them may be simple to solve. The programmer is
required to write functions for each of these modules and finally arrange these functions in
the proper
Page 7
7
II. BASIC INPUT/OUTPUT
C++ uses a convenient abstraction called streams to perform input and output
operations in sequential media such as the screen or the keyboard. A stream is an
object where a program can either insert or extract characters to/from it. We do not
really need to care about many specifications about the physical media associated
with the stream - we only need to know it will accept or provide characters
sequentially. The standard C++ library includes the header file iostream, where the
standard input and output stream objects are declared.
Standard Output (cout)
By default, the standard output of a program is the screen, and the C++ stream object defined
to access it is cout. It is used in conjunction with the insertion operator, which is written as
<< (two "less than" signs).
cout << "Output sentence"; // prints Output sentence on screen
cout << 120; // prints number 120 on screen
cout << x; // prints the content of x on screen
The << operator inserts the data that follows it into the stream preceding it. In the
examples above it inserted the constant string Output sentence, the numerical constant 120
and variable x into the standard output stream cout. Notice that the sentence in the first
instruction is enclosed between double quotes (") because it is a constant string of
characters. Whenever we want to use constant strings of characters we must enclose them
between double quotes (") so that they can be clearly distinguished from variable names.
For example, these two sentences have very different results:
cout << "Hello"; // prints Hello
cout << Hello; // prints the content of Hello variable
The insertion operator (<<) may be used more than once in a single statement:
cout << "Hello, " << "I am " << "a C++ statement";
Page 8
8
This last statement would print the message Hello, I am a C++ statement on the
screen. The utility of repeating the insertion operator (<<) is demonstrated when we want to
print out a combination of variables and constants or more than one variable:
cout << "Hello, I am " << age << " years old and my zipcode is " <<
zipcode;
If we assume the age variable to contain the value 24 and the zipcode variable to
contain 90064 the output of the previous statement would be:
Hello, I am 24 years old and my zipcode is 90064
It is important to notice that cout does not add a line break after its output unless we
explicitly indicate it, therefore, the following statements:
cout << "This is a sentence.";
cout << "This is another sentence.";
will be shown on the screen one following the other without any line break between them:
This is a sentence. This is another sentence.
even though we had written them in two different insertions into cout. In order to perform a
line break on the output we must explicitly insert a new-line character into cout. In C++ a
new-line character can be specified as \n (backslash, n):
cout << "First sentence.\n";
cout << "Second sentence.\nThird
sentence.";
This produces the following output:
First sentence.
Second sentence.
Third sentence.
Additionally, to add a new-line, you may also use the endl manipulator. For example:
1
2
cout << "First sentence." << endl;
cout << "Second sentence." << endl;
Page 9
9
would print out:
First sentence.
Second sentence.
The endl manipulator produces a newline character, exactly as the insertion of ' \n'
does, but it also has an additional behavior when it is used with buffered streams: the buffer
is flushed. Anyway, cout will be an unbuffered stream in most cases, so you can generally
use both the \n escape character and the endl manipulator in order to specify a new line
without any difference in its behavior.
Standard Input (cin).
The standard input device is usually the keyboard. Handling the standard input in C++ is
done by applying the overloaded operator of extraction (>>) on the cin stream. The operator
must be followed by the variable that will store the data that is going to be extracted from
the stream. For example:
int age;
cin >> age;
The first statement declares a variable of type int called age, and the second one waits for
an input from cin (the keyboard) in order to store it in this integer variable.
cin can only process the input from the keyboard once the RETURN key has been pressed.
Therefore, even if you request a single character, the extraction from cin will not process
the input until the user presses RETURN after the character has been introduced.
You must always consider the type of the variable that you are using as a container with cin
extractions. If you request an integer you will get an integer, if you request a character you
will get a character and if you request a string of characters you will get a string of
characters.
Page 10
10
// i/o example
#include <iostream>
int main ()
{
int i;
cout << "Please enter an integer value: ";
cin >> i;
cout << "The value you entered is " << i;
cout << " and its double is " << i*2 << ".\n";
return 0;
}
The user of a program may be one of the factors that generate errors even in the
simplest programs that use cin (like the one we have just seen). Since if you request an
integer value and the user introduces a name (which generally is a string of characters), the
result may cause your program to misoperate since it is not what we were expecting from
the user. So when you use the data input provided by cin extractions you will have to trust
that the user of your program will be cooperative and that he/she will not introduce his/her
name or something similar when an integer value is requested. A little ahead, when we see
the stringstream class we will see a possible solution for the errors that can be caused by
this type of user input.
You can also use cin to request more than one datum input from the user:
cin >> a >> b;
is equivalent to:
cin >> a;
cin >> b;
In both cases the user must give two data, one for variable a and another one for variable b
that may be separated by any valid blank separator: a space, a tab character or a newline.
cin and strings
We can use cin to get strings with the extraction operator (>>) as we do with fundamental
data type variables:
cin >> mystring;
Page 11
11
However, as it has been said, cin extraction stops reading as soon as if finds any blank
space character, so in this case we will be able to get just one word for each extraction. This
behavior may or may not be what we want; for example if we want to get a sentence from
the user, this extraction operation would not be useful.
In order to get entire lines, we can use the function getline, which is the more
recommendable way to get user input with cin:
// cin with strings
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string mystr;
cout << "What's your name? ";
getline (cin, mystr);
cout << "Hello " << mystr << ".\n";
cout << "What is your favorite team? ";
getline (cin, mystr);
cout << "I like " << mystr << " too!\n";
return 0;
}
Notice how in both calls to getline we used the same string identifier (mystr). What the
program does in the second call is simply to replace the previous content by the new one
that is introduced.
stringstream
The standard header file <sstream> defines a class called stringstream that allows a string-
based object to be treated as a stream. This way we can perform extraction or insertion
operations from/to strings, which is especially useful to convert strings to numerical values
and vice versa. For example, if we want to extract an integer from a string we can write:
string mystr ("1204");
int myint;
stringstream(mystr) >> myint;
Page 12
12
This declares a string object with a value of "1204", and an int object. Then we use
stringstream's constructor to construct an object of this type from the string object. Because
we can use stringstream objects as if they were streams, we can extract an integer from it as
we would have done on cin by applying the extractor operator (>>) on it followed by a
variable of type int.
After this piece of code, the variable myint will contain the numerical value 1204.
// stringstreams
#include <iostream>
#include <string>
#include <sstream>
int main ()
{
string mystr;
float price=0;
int quantity=0;
cout << "Enter price: ";
getline (cin,mystr);
stringstream(mystr) >> price;
cout << "Enter quantity: ";
getline (cin,mystr);
stringstream(mystr) >> quantity;
cout << "Total price: " << price*quantity << endl;
return 0;
}
In this example, we acquire numeric values from the standard input indirectly.
Instead of extracting numeric values directly from the standard input, we get lines from the
standard input (cin) into a string object (mystr), and then we extract the integer values from
this string into a variable of type int (quantity). Using this method, instead of direct
extractions of integer values, we have more control over what happens with the input of
numeric values from the user, since we are separating the process of obtaining input from
the user (we now simply ask for lines) with the interpretation of that input. Therefore, this
method is usually preferred to get numerical values from the user in all programs that are
intensive in user input.
Page 13
13
III. CLASSES AND OBJECTS
CLASSES
In C++, class is a user defined data type that binds data describing an entity and its associated
functions together under a single unit
1 Attributes of a Class
The declaration of a class involves the declaration of its four attributes.
1. Data Members, which are the data type properties that describe the characteristics
of a class. There may be zero or more data members.
2. Member Functions, which are the set of operations that may be applied to the
objects of the class. There may be zero or more member function and they are
also referred to as the class interface.
3. Access Labels, which are the keywords that control the access to members of a
class within the program. They are private, protected and public.
4. Class Tag, which serves as a type specifier for the class, using which objects are
created.
The Class Definition
The syntax for-defining a class is as follows:
class ClassName
{
private:
Variable declaration;
Function declaration;
public:
Variable declaration;
Function declaration;
protected:
Variable declaration;
Function declaration;
};
The class specifies the type and scope of its members. The keyword class indicates that
the name which follows (class name - an identifier supplied by the user) is an abstract
data type. The body of a class is enclosed within the curly braces followed by a semicolon.
Page 14
14
The body of a class contains declaration of variables and functions, collectively known as
members. The variables declared inside a class are known as data members and functions
are known as member functions (also known as class methods).These members are
usually grouped under three sections: private, public and protected, which define the
accessibility ( or visibility) of members.
Access Labels
Access label, otherwise known as access,- control specifiers, define the visibility
of the members of a class. The keywords private, public and protected are used as
the access labels and they have the impact on the class members as follows:
Private members (data and function) are hidden from the outside world and they
implement the OOP concept data hiding. That is, these members are accessible
only to there on class’s members
Public members are not only accessible to their own members, but also from
outside the class. The keyword public provides class members the public
interface.
Protected members are similar to private members, but they differ in the
context of inheritance.
The members declared in the beginning of class without any access specifier are private
by default. Hence the first use of the access label private in a class is optional. A class
which is totally private is hidden from the external world and will not serve any useful
purpose.
Object Declaration
Once a class is defined, you can declare objects of that type. The syntax for declaring a object
is the same as that for declaring any other variable. The following statements declare two
objects of type student: student st1, st2;
Accessing Class Members
Once an object of a class is declared, it can access the public members of the class. st1.getdata();
Definition of Member Functions
The data members of a class must be declared within the body of the class, whereas
Page 15
15
the member functions of the class can be defined in any one of the following ways:
Inside the class specification
Outside the class specification
The member functions (class methods) can be defined either inside or outside the class
definition. If the class methods are defined inside, the function header and its body
will be placed inside the class. If the function is defined outside the class, its prototype
should be placed inside the class and the definition needs the following syntax:
ReturnType ClassName::FunctionName(ParameterList)
{
FunctionBody;
}
The symbol :: is called scope resolution operator and it is used to qualify the
members of a class.
Scope Resolution Operator ::
C++ supports a mechanism to access a global variable from a function in which a local
variable is defined with the same name as that of the global variable. It is
achieved using the scope resolution operator The syntax for accessing a global variable
using the scope resolution operator is as follows:
: :GlobalVariableName
The scope resolution operator permits a program to reference an identifier
in the global scope that has been hidden by another identifier with the same
name in the local scope
Another use of scope resolution operator is to qualify the member function of a
class. When the function is to be defined outside the class specification, the function header
should have the following syntax:
The scope resolution operator is also used to define and initialize the static data
members of a class.
Nested Classes
A class declared inside another class is called nested class. The outer class is known as
enclosing class.
Page 16
16
Structure v/s Classes
Structure Class
1. The keyword struct is used to define.
The members are data elements
only and there is no member
function.
2. No access labels for the members.
3. The members are public by default.
4. Variable declared with structure tag
is known as structure variable.
5. There are no static members.
1. The keyword class is used in definition.
2. Both data and functions are used a
members.
3. Access labels sets the scope of members.
4. By default, the members are private.
5. Variable declared with el-ass ar
known as objects.
6. There may be static members.
FUNCTIONS IN CLASSES
A variety of operations are to be performed for the data members of a class and we
have seen that a class contains functions as its members to carry out these operations. A class
can contain different types of functions. We have already discussed the inline functions.
Now let us have a brief look at some other functions.
1. Friend Function
Friend function is a non member function that is granted access to the private and
protected members of a class. To declare a non-member function as friend of a class, the
prototype declaration of the function should be included in the class definition. The
declaration should begin with the keyword friend followed by function name and an object
of the class (to which the function makes friendship) as argument. But the keyword friend
is not used in the actual definition of the function, which obviously takes place outside the
class.
Consider the following example:
c l a s s ABC {
int a;
float b;
Page 17
17
public:
void print()
{
cout « a*b;
}
friend float sum(ABC); //prototype of friend function
};
float sum(ABC ob) //definition of friend function
{
return (ob.a + ob.b); //accessing private members
}
Here the non-member function sum(ABC) is a friend function to the class ABC.
Hence the private members a and b, which are normally inaccessible to an external function
like sum(), are now accessible to sum() being a friend function. Now let us brief the
features of friend functions as follows:
A function may be declared friend of more than one class. .
It does not have the class scope; rather it depends upon its original declaration and
definition.
A friend function cannot be called using the object of that class; it is not in the
scope of a class.
It can be invoked like a normal function. That is, it does not require the dot operator
prefixed by the object.
Since it is not a member function, it cannot access the class members directly
but has to use the object name as the parameter and the membership operator (.)
with each member name.
It can be declared privately or publicly in the class without affecting its
meaning.
2. Inline functions
The member functions defined inside the class are automatically inline. The defin on
does not require the keyword inline. Hence only small member functions need to be
defined inside the class. If the member function defined outside the class need to be an inline
function, the keyword inline should be used in the function header as shown below:
inline ReturnType ClassName :: FunctionName (Arguments)
{
//Body_of_Function
}
Page 18
18
Ordinary Function v/s Inline Function
The distinction between normal functions and inline functions is the different
compilation process for them. The following steps are carried out, when the executable code
of the program (machine language version) is run.
The set of instructions constituting the program is loaded in the memory in specific
locations and they will be executed in the specified order.
Meanwhile when a function calling statement is encountered, the following steps are
performed by the Operating System.
Stores the memory address of the instruction immediately following the function
call statement.
Loads the function code being called into the memory.
Copies argument values, if any.
Jumps to the memory location of the called function.
Executes the function body.
Stores the value returned by the function.
Jumps back to the address of the instruction that was saved before jumping to the
called function.
Execution of the next instruction after the function calling statement continues.
The foresaid steps will be continued till the program terminates.
The inlining does not work with the following situations:
For functions that return value's and are having a loop or a switch or a go to
For functions not returning values, if a return statement exists.
For functions containing static variables.
For recursive functions-.
Lab
1. Create a class Calc which consist of 2 data member and member functions for
calculating sum, difference, product and division
2. Define a class box to find the volume of the box.
3. Write a class for finding prime number
Page 19
19
4. Create a class Students and prepare mark list
5. Write a program to read and print the details such as id, name and mark of n students
in a class.
6. Define a class to represent a bank account. Data members: name of depositor,
AccNo, Type of account and balance amount in the account. Member functions
i. To assign initial value.
ii. To deposit an amount
iii. To withdraw an amount after checking the balance
iv. To display the name and balance
Write a main program to test the program.
7. Modify the above program for handling 10 customers.
8. Find the mean value using friend function
9. Create two classes DM and DB which stores the value of distances. DM stores
distances in meters and centimeters and DB in feet and inches. Write a program that
can read values for the class objects and add one object DM with another object of
DB. Use friend function.
10. Write a program to swap the private data of two classes using friend function
11. Define a class person having member variables id, name and age. Define a friend
function to find who is elder.
Page 20
20
IV. CONSTRUCTORS AND DESTRUCTORS
A constructor is a special member function with the same name as that of the class
name and is executed when an object is created.
For example, in the DayOfYear class in this program we might have:
class DayOfYear
{
public:
DayOfYear (int monthValue, int dayValue);
//Initializes the month and day to arguments.
DayOfYear (int monthValue);
//Initializes the date to the first of the given month.
DayOfYear ( );
//Initializes the date to January 1.
void input( );
...
private:
int month;
int day;
void testDate( ); // a private member function
};
where we see three constructors, each with a different number of arguments. A constructor
must have the same name as the class and cannot return a value. Above we see part of the
interface for the DayOfYear class.
Constructors may not be explicitly called like other member functions(e.g.
date1.DayOfYear(7,4) is illegal). A constructor can be explicitly called when used to
initialize a new instance, such as
DayOfYear date1; // default constructor called here
DayOfYear date2; // default constructor called here
date1 = DayOfYear(12,25); // 2 argument constructor explicitly called
here
date2 = DayOfYear(); // call the default constructor
A default constructor is supplied for you if you have not explicitly defined any constructors.
Once you define a constructor, however, you should be sure to also create a default
constructor (with no arguments). Otherwise a declaration with no arguments (e.g. DayOfYear
date1) would be illegal.
Page 21
21
Characteristics of Constructors
It has the same name as that of its class.
It is executed automatically when an object is created.
If a class has a constructor, each before any use is made of the object of that class
will be initialized before any use is made of the object
Constructors obey the access rules as usual.
It does not have return type.
A constructor may not be static.
It is not possible to take the address of a constructor.
An object of a class with a constructor cannot be member of a union.
Member functions may be called from within a constructor.
Default constructors and copy constructors are generated by the
compiler where needed, if there are no user defined
constructors. Generated constructors are public.
Types of constructors
1. Parameterized constructors
Constructors that can take arguments are termed as parameterized constructors. The number
of arguments can be greater or equal to one(1). For example:
class example
{
int p, q;
public:
example(int a, int b); //parameterized
constructor
};
example :: example(int a, int b)
{
p = a;
q = b;
}
When an object is declared in a parameterized constructor, the initial values have to be passed
as arguments to the constructor function. The normal way of object declaration may not
Page 22
22
work. The constructors can be called explicitly or implicitly.The method of calling the
constructor implicitly is also called the shorthand method.
example e = example(0, 50); //explicit call
example e(0, 50); //implicit call
2. Default constructors
If the programmer does not supply a constructor for an instantiable class, a typical compiler
will provide a default constructor. The behavior of the default constructor is language
dependent. It may initialize data members to zero or other same values, or it may do nothing
at all.
3. Copy constructors
Copy constructors define the actions performed by the compiler when copying class objects.
A copy constructor has one formal parameter that is the type of the class (the parameter may
be a reference to an object).
It is used to create a copy of an existing object of the same class. Even though both classes
are the same, it counts as a conversion constructor.
Constructor overloading
Constructors, used to create instances of an object, may also be overloaded in some
object oriented programming languages. Because in many languages the constructor’s name
is predetermined by the name of the class, it would seem that there can be only one
constructor. Whenever multiple constructors are needed, they are implemented as overloaded
functions. A default constructor takes no parameters, instantiating the object members with a
value zero. For example, a default constructor for a restaurant bill object written in C++
might set the Tip to 15%:
Bill()
{
tip = 15.0;
total = 0.0;
}
The drawback to this is that it takes two steps to change the value of the created Bill object.
The following shows creation and changing the values within the main program:
Page 23
23
Bill cafe;
cafe.tip = 10.00;
cafe.total = 4.00;
By overloading the constructor, one could pass the tip and total as parameters at creation.
This shows the overloaded constructor with two parameters:
Bill(double setTip, double setTotal)
{
tip = setTip;
total = setTotal;
}
Now a function that creates a new Bill object could pass two values into the constructor and
set the data members in one step. The following shows creation and setting the values:
Bill cafe(10.00, 4.00);
This can be useful in increasing program efficiency and reducing code length.
DESTRUCTOR
The destructor has the same name as the class, but with a tilde (~) in front of it. If the
object was created as an automatic variable, its destructor is automatically called when it goes
out of scope. If the object was created with a new expression, then its destructor is called
when the delete operator is applied to a pointer to the object. Usually that operation occurs
within another destructor, typically the destructor of a smart pointer object.
A destructor should never throw an exception.
Example
#include <iostream>
#include <string>
class foo
{
public:
foo( void )
{
print( "foo()" );
}
~foo( void )
{
print( "~foo()" );
}
void print( std::string const& text )
{
Page 24
24
std::cout << static_cast< void* >( this ) <<
" : " << text << std::endl;
}
/*
Disable copy-constructor and assignment operator by
making them private
*/
private:
foo( foo const& );
foo& operator = ( foo const& );
};
int main( void )
{
foo array[ 3 ];
/*
When 'main' terminates, the destructor is invoked for
each element
in 'array' (the first object created is last to be
destroyed)
*/
}
IV. FUNCTION OVERLOADING AND
INHERITANCE
Polymorphism
Polymorphism is defined as one interface to control access to a general class of
actions. There are two types of polymorphism.
1. Compile time polymorphism
Eg: Function overloading and Operator overloading
2. Run time polymorphism: - Runtime time polymorphism is done using inheritance and
virtual functions.
Page 25
25
Function Overloading
Polymorphism means that functions assume different forms at different times. In case
of compile time it is called function overloading. For example, a program can consist of two
functions where one can perform integer addition and other can perform addition of floating
point numbers but the name of the functions can be same such as add. The function add() is
said to be overloaded. Two or more functions can have same name but their parameter list
should be different either in terms of parameters or their data types. The functions which
differ only in their return types cannot be overloaded. The compiler will select the right
function depending on the type of parameters passed. In cases of classes constructors could
be overloaded as there can be both initialized and unintialized objects. Here is a program
which illustrates the working of compile time function overloading and constructor
overloading.
#include<iostream.h>
class employee
{
public:
int week;
int year;
double calculate(double salary)
{
return(salary*week);
}
int calculate(int salary)
{
return(salary*week*year);
}
employee(int week1)
{
week=week1;
}
employee(int week1,int year1)
{
week=week1;
year=year1;
}
};
void main()
{
int sal;
double sal2;
employee emp1(10);
employee emp2(10,3);
Page 26
26
cout << "Enter the no years for first employee" << endl;
cin >> emp1.year;
cout << endl << "Enter the salary per week for first employee" << endl;
cin >> sal;
cout << "The total salary of first employee is : " << emp1.calculate(sal) <<
endl;
cout << endl << "Enter the salary per week for second employee is : " << endl;
cin >> sal2;
cout << "The total salary of second employee is for one year: " <<
emp2.calculate(sal2) << endl;
return(0);
}
In the program function calculate() and constructor of class employee are overloaded. The
function calculate() is declared two times but with different parameter type and same with
constructor employee which is also declared two times but with different parameter types.
The following statements
double calculate(double salary)
{
return(salary*week);
}
int calculate(int salary)
{
return(salary*week*year);
}
declare functions with same name calculate but one has parameter type integer and other has
parameter type double. The function calculate() is overloaded. The statements
employee(int week1)
{
week=week1;
}
Page 27
27
employee(int week1,int year1)
{
week=week1;
year=year1;
}
declare two constructors of class employee where one constructor’s parameter list is different
from other constructor’s parameter list. The constructor is overloaded. The statement
employee emp1(10);
declares an object emp1 of type employee. When object is created first constructor is called
since the argument list matches with parameter list of the constructor. The constructor
initializes the data member week of the object emp1. The statement
employee emp2(10,3);
declares an object emp2 of type employee. The second constructor is called since the
argument list matches with the parameter list of the constructor. The constructor initializes
the data members week and year of the object emp2. In the statement
cout << "The total salary of first employee is : " << emp1.calculate(sal) << endl;
emp1.calculate(sal) calls the first function calculate as the data type of sal matches with the
parameter of the function calculate. It displays the total salary which is salary*week*year. In
the following statement
cout << "The total salary of second employee is for one year: " <<
emp2.calculate(sal2) << endl;
emp2.calculate(sal2) calls the second function calculate as the data type of sal2 which is
double matches with the data type of parameter of function calculate and hence second
function is called. It displays the total salary which is salary*week.
Operator Overloading
In polymorphism operators can also be overloaded. Operators can be overloaded in
order to perform special functions with respect to the class. With the help of operator
overloading standard operations such as + , - , * , etc can be applied on the objects of the
Page 28
28
class. Operators are overloaded by creating operator functions. The keyword operator is used
to define operator function. Operator overloading doesn’t allow creating new operators. The
general form of operator function is:-
return_type operator #(arg_list)
{
}
return_type is the data type of the value returned from the function. The arg_list is the list of
the arguments to the function. The operator comes after the keyword operator. Instead of #
there will be an operator. Here is a program to show operator overloading.
#include<iostream>
class rectangle
{
public:
int length;
int breadth;
rectangle(int length1,int breadth1)
{
length=length1;
breadth=breadth1;
}
int operator+(rectangle r1)
{
return(r1.length+length);
}
};
void main ()
{
rectangle r1(10,20);
rectangle r2(40,60);
int len;
len=r1+r2;
cout << "The total length of the two rectangles is : " << len << endl;
}
The program consists of operator + function which is overloaded. The + operator is
used to perform addition of the length of the objects. The statements
int operator+(rectangle r1)
{
return(r1.length+length);
Page 29
29
}
define the operator function whose return type is integer. The operator + is overloaded. The
function is used to add the lengths of the two objects. The parameter list consists of one
object of type rectangle. The operator()+ takes only one parameter as the operand on the left
side of the operator + is passed implicitly to the function through the this operator. The
statement
len=r1+r2;
calls the operator()+ function to calculate the length of the two objects. The return type is of
integer. The variable len will contain the total of length of the objects.
INHERITANCE
The technique of building new classes from the existing is called inheritance. In
object-oriented programming (OOP), inheritance is a way to reuse code of existing objects. In
classical inheritance where objects are defined by classes, classes can inherit attributes and
behavior from pre-existing classes called base classes (super classes, parent classes or
ancestor classes). The resulting classes are known as derived classes (subclasses or child
classes).
Applications
Inheritance is used to co-relate two or more classes to each other.
1. Overriding
Many object-oriented programming languages permit a class or object to replace the
implementation of an aspect—typically a behavior—that it has inherited. This process is
usually called overriding.
2. Code reuse
Implementation inheritance is the mechanism whereby a subclass re-uses code in a base class.
By default the subclass retains all of the operations of the base class, but the subclass may
override some or all operations, replacing the base-class implementation with its own.
Page 30
30
Base & Derived Classes:
A class can be derived from more than one classes, which means it can inherit data and
functions from multiple base classes. To define a derived class, we use a class derivation list
to specify the base class (es). A class derivation list names one or more base classes and has
the form:
class derived-class: access-specifier base-class
Where access-specifier is one of public, protected, or private, and base-class is the name of
a previously defined class. If the access-specifier is not used, then it is private by default.
Consider a base class Shape and its derived class Rectangle as follows:
#include <iostream>
class Shape // Base class
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
class Rectangle: public Shape // Derived class
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
cout << "Total area: " << Rect.getArea() << endl; // Print the area of
the object.
}
When the above code is compiled and executed, it produces following result:
Page 31
31
Total area: 35
Access Control and Inheritance:
A derived class can access all the non-private members of its base class. Thus base-
class members that should not be accessible to the member functions of derived classes
should be declared private in the base class.
We can summarize the different access types according to who can access them in the
following way:
Access public protected private
Same class yes yes yes
Derived classes yes yes no
Outside classes yes no no
A derived class inherits all base class methods with the following exceptions:
Constructors, destructors and copy constructors of the base class.
Overloaded operators of the base class.
The friend functions of the base class.
FORMS OF INHERITANCE
1. Single Inheritance: It is the inheritance hierarchy wherein one derived class inherits
from one base class.
2. Multiple Inheritance: It is the inheritance hierarchy wherein one derived class
inherits from multiple base class(es)
3. Hierarchical Inheritance: It is the inheritance hierarchy wherein multiple subclasses
inherit from one base class.
4. Multilevel Inheritance: It is the inheritance hierarchy wherein subclass acts as a base
class for other classes.
Page 32
32
5. Hybrid Inheritance: The inheritance hierarchy that reflects any legal combination of
other four types of inheritance.
Visibility Mode: It is the keyword that controls the visibility and availability of inherited
base class members in the derived class. It can be either private or protected or public.
Private Inheritance: It is the inheritance facilitated by private visibility mode. In private
inheritance; the protected and public members of base class become private members of the
derived class.
Public Inheritance: It is the inheritance facilitated by public visibility mode. In public
inheritance ,the protected members of base class become protected members of the derived
class and public members of the base class become public members of derived class.;
Protected Inheritance: It is the inheritance facilitated by protected visibility mode.In
protected inheritance, the protected and public members of base class become protected
members of the derived class.
Base Class Visibility Derived class visibility
Public derivation Private derivation Protected derivation
Private Not inherited Not inherited Not inherited
Protected Protected Private Protected
Public Public Private Protected
Containership: When a class contains objects of other class types as its members, it is called
containership. It is also called containment, composition, aggregation.
Execution of base class constructor
Method of inheritance Order of execution
class B : public A { }; A(); base constructor
B(); derived constructor
class A : public B, public C B();base (first)
C();base (second)
A();derived constructor
Page 33
33
When both derived and base class contains constructors, the base constructor is executed first
and then the constructor in the derived class is executed. In case of multiple inheritances, the
base classes are constructed in the order in which they appear in the declaration of the derived
class.
1. Single Inheritance
Program: payroll system using single inheritance
#include<iostream.h>
#include<conio.h>
class emp
{
public:
int eno;
char name[20],des[20];
void get()
{
cout<<"Enter the employee number:";
cin>>eno;
Page 34
34
cout<<"Enter the employee name:";
cin>>name;
cout<<"Enter the designation:";
cin>>des;
}
};
class salary:public emp
{
float bp,hra,da,pf,np;
public:
void get1()
{
cout<<"Enter the basic pay:";
cin>>bp;
cout<<"Enter the Humen Resource Allowance:";
cin>>hra;
cout<<"Enter the Dearness Allowance :";
cin>>da;
cout<<"Enter the Profitablity Fund:";
cin>>pf;
}
void calculate()
{
np=bp+hra+da-pf;
}
void display()
{
cout<<eno<<"\t"<<name<<"\t"<<des<<"\t"<<bp<<"\t"<<hra<<"\t"<<da<<"\t"<<pf<<"\t
"<<np<<"\n";
}
};
void main()
Page 35
35
{
int i,n;
char ch;
salary s[10];
clrscr();
cout<<"Enter the number of employee:";
cin>>n;
for(i=0;i<n;i++)
{
s[i].get();
s[i].get1();
s[i].calculate();
}
cout<<"\ne_no \t e_name\t des \t bp \t hra \t da \t pf \t np \n";
for(i=0;i<n;i++)
{
s[i].display();
}
getch();
}
Output: Enter the Number of employee:1
Enter the employee No: 150
Enter the employee Name: ram
Enter the designation: Manager
Enter the basic pay: 5000
Enter the HR allowance: 1000
Enter the Dearness allowance: 500
Enter the profitability Fund: 300
E.No E.name des BP HRA DA PF NP
Page 36
36
150 ram Manager 5000 1000 500 300 6200
2. Multiple Inheritance
To find out the student details using multiple inheritance.
Program:
#include<iostream.h>
#include<conio.h>
class student
{
protected:
int rno,m1,m2;
public:
void get()
{
cout<<"Enter the Roll no :";
cin>>rno;
cout<<"Enter the two marks :";
cin>>m1>>m2;
}
};
class sports
{
protected:
int sm; // sm = Sports mark
public:
void getsm()
{
cout<<"\nEnter the sports mark :";
cin>>sm;
}
};
class statement:public student,public sports
Page 37
37
{
int tot,avg;
public:
void display()
{
tot=(m1+m2+sm);
avg=tot/3;
cout<<"\n\n\tRoll No : "<<rno<<"\n\tTotal :
"<<tot;
cout<<"\n\tAverage : "<<avg;
}
};
void main()
{
clrscr();
statement obj;
obj.get();
obj.getsm();
obj.display();
getch();
}
Output:
Enter the Roll no: 100
Enter two marks
90
80
Enter the Sports Mark: 90
Roll No: 100
Total : 260
Average: 86.66
Page 38
38
Virtual Functions
We may face a problem in multiple inheritance, when a function with the same name
appears in more than one base class. Compiler shows ambiguous error when derived class
inherited by these classes uses this function. A virtual function is a member function of the
base class and which is redefined by the derived class. When a derived class inherits the class
containing the virtual function, it has ability to redefine the virtual functions. A virtual
function has a different functionality in the derived class. The virtual function within the base
class provides the form of the interface to the function. Virtual function implements the
philosophy of one interface and multiple methods. The virtual functions are resolved at the
run time. This is called dynamic binding. The functions which are not virtual are resolved at
compile time which is called static binding. A virtual function is created using the keyword
virtual which precedes the name of the function as below:
class P : public M, public N //multiple inheritance
{
public :
void display() //overrides display() of M and N
{
M::display()
}
};
we can now used the derived class as follows :
void main()
{
P obj;
obj.display();
}
Virtual functions are accessed using a base class pointer. A pointer to the base class
can be created. A base class pointer can contain the address of the derived object as the
derived object contains the subset of base class object. Every derived class is also a base
class. When a base class pointer contains the address of the derived class object, at runtime it
is decided which version of virtual function is called depending on the type of object
contained by the pointer. Here is a program which illustrates the working of virtual functions.
include<iostream.h>
class shape
{
Page 39
39
public:
int side;
virtual int volume()
{
cout << endl <<"Virtual function of base class " << endl;
}
};
class cube: public shape
{
public:
int volume()
{
cout << endl << "Volume function of cube " << endl;
return(side*side*side);
}
};
class cuboid:public shape
{
public:
int breadth;
int height;
int volume()
{
cout << endl << "Volume function of cuboid " << endl;
return(side*breadth*height);
}
};
void main()
{
shape *s,s1;
cube c1;
cuboid c2;
cout << "Enter the side of the cube" << endl;
cin >> c1.side;
cout << endl << "Enter the side of the cuboid " << endl;
cin >> c2.side;
cout << endl << "Enter the breadth of the cuboid" << endl;
cin >> c2.breadth;
cout << endl << "Enter the height of the cuboid" << endl;
cin >> c2.height;
s=&s1;
s->volume();
s=&c1;
cout << endl << "The volume of the cube " << s->volume() << endl;
s=&c2;
cout << endl << "The volume of the cuboid " << s->volume() << endl;
}
The program has base class shape and class cube and cuboid which inherits base class. The
base class has virtual function volume. The statements
Page 40
40
virtual int volume()
{
cout << endl <<"Virtual function of base class " << endl;
return(0);
}
define the member function volume() of base class. The function is virtual. The keyword
virtual precedes the function return type. In the following statements
int volume()
{
cout << endl << "Volume function of cube " << endl;
return(side*side*side);
}
the derived class cube which inherits base class shape, redefines the function volume() which
is virtual. In the following statements
int volume()
{
cout << endl << "Volume function of cuboid " << endl;
return(side*breadth*height);
}
the derived class cuboid which inherits the base class shape, redefines the function volume().
The statement
shape *s,s1;
declares a pointer to the base class shape. The statement
s=&s1;
pointer s contains the address of the base class object s1. The statement
s->volume();
Page 41
41
calls the function volume of the base class shape as the pointer contains the address of the
base class object. The statement
s=&c1;
pointer s now contains the address of the derived class object c1. The statement
cout << endl << "The volume of the cube " << s->volume() << endl;
displays the volume of the cube as s->volume() calls the function volume of the derived class
cube. The pointer s contains the address of the object of derived class cube. In the statement
s=&c2;
pointer s now contains the address of the derived class object c2. The statement
cout << endl << "The volume of the cuboid " << s->volume() << endl;
displays the volume of the cuboid as s->volume() calls the function volume of the derived
class cuboid. The pointer s now contains the address of the object of derived class cuboid.
When a virtual function is not defined by the derived class, the version of the virtual
function defined by the base class is called. When a derived class which contains the virtual
function is inherited by another class, virtual function can be overloaded for the new derived
class. This means that virtual function can be inherited.
A pure virtual function is a function which contains no definition in the base class. The
general form of virtual function is:-
virtual return_type function_name(para_list)=0;
The return_type is the type of the value returned. The function_name is the name of the
function and para_list is the parameter list.
Each derived class should contain the definition of virtual functions. If the derived class does
not define virtual function then compiler will generate an error. A class which contains one or
more pure virtual function is called abstract class. Objects of abstract class cannot be created
as it does not contain definition of one or more functions. The pointers of abstract class can
be created and the references to the abstract class can be made. Here is a same program which
shows how pure virtual function is defined.
Page 42
42
#include<iostream.h>
class shape
{
public:
int side;
virtual int volume()=0;
};
class cube: public shape
{
public:
int volume()
{
cout << endl << "Volume function of cube " << endl;
return(side*side*side);
}
};
class cuboid:public shape
{
public:
int breadth;
int height;
int volume()
{
cout << endl << "Volume function of cuboid " << endl;
return(side*breadth*height);
}
};
void main()
{
shape *s;
cube c1;
cuboid c2;
cout << "Enter the side of the cube" << endl;
cin >> c1.side;
cout << endl << "Enter the side of the cuboid " << endl;
cin >> c2.side;
cout << endl << "Enter the breadth of the cuboid" << endl;
cin >> c2.breadth;
cout << endl << "Enter the height of the cuboid" << endl;
cin >> c2.height;
s=&c1;
cout << endl << "The volume of the cube " << s->volume() << endl;
s=&c2;
cout << endl << "The volume of the cuboid " << s->volume() << endl;
}
The statement
virtual int volume()=0;
declares pure virtual function volume() which has no definition. The class shape is now
abstract class and objects of type shape cannot be created.
Page 43
43
Virtual Base Class
Multipath inheritance may lead to duplication of inherited members from a
grandparent base class. This may be avoided by making the common base class a virtual base
class. When a class is made a virtual base class, C++ takes necessary care to see that only one
copy of that class is inherited.
class A
{
....
....
};
class B1 : virtual public A
{
....
....
};
class B2 : virtual public A
{
....
....
};
class C : public B1, public B2
{
.... // only one copy of A
.... // will be inherited
};
Abstract Class
An abstract class is one whose role is only meant to lay a foundation for other classes
that would need a common behavior or similar characteristics. Therefore, an abstract class is
used only as a base class for inheritance. A class is made abstract by declaring its methods as
"pure" virtual methods.
Only a virtual method can be made "pure". The syntax of declaring a pure virtual method is:
virtual ReturnType MethodName() = 0;
The virtual keyword is required to make sure that a (any) child of this class can implement
this method as it judges it necessary. The ReturnType is the data type that the method will
Page 44
44
return. The MethodName is an appropriate name for the method. The = 0 expression is
required to let the compiler know that this method is pure virtual.
When creating an abstract class, you can declare all of its methods as pure. Here is an
example:
public ref class CQuadrilateral
{
public:
virtual double Perimeter() = 0;
virtual double Area() = 0;
};
To indicate that the class is abstract, type the abstract keyword after its name. Here is an
example:
public ref class CQuadrilateral abstract
{
public:
virtual double Perimeter() = 0;
virtual double Area() = 0;
};
In C++/CLI, if you omit the abstract keyword, you would receive a warning.
Not all methods of an abstract class have to be pure virtual. This means that regular virtual
methods can also be members of an abstract class. Here is an example:
public ref class CQuadrilateral abstract
{
public:
virtual String ^ Description();
virtual double Perimeter() = 0;
virtual double Area() = 0;
virtual void Display() = 0;
};
A property can also be a member of an abstract class. If you declare a property in an abstract
class, don't use the = 0 expression on the property. Here is an example:
public ref class CQuadrilateral abstract
{
public:
virtual property double Base;
virtual String ^ Description();
virtual double Perimeter() = 0;
virtual double Area() = 0;
virtual void Display() = 0;
};
Page 45
45
You can also add regular member variables in an abstract class. You can even make some
private, some public, and some protected. Here are examples:
public ref class CQuadrilateral abstract
{
private:
double bs;
protected:
String ^ Name;
public:
virtual property double Base;
virtual String ^ Description();
virtual double Perimeter() = 0;
virtual double Area() = 0;
virtual void Display() = 0;
};
An abstract class can also have one or more constructors:
public ref class CQuadrilateral abstract
{
private:
double bs;
protected:
String ^ Name;
public:
virtual property double Base;
virtual String ^ Description();
virtual double Perimeter() = 0;
virtual double Area() = 0;
virtual void Display() = 0;
CQuadrilateral();
};
When a class is defined as abstract, you can implement any of its properties if you want. If a
method is not made pure virtual, you can also define it. Here are examples:
public ref class CQuadrilateral abstract
{
private:
double bs;
public:
String ^ Name;
virtual property double Base
{
double get() { return bs; }
void set(double b)
{
if( b <= 0 )
bs = 0.00;
Page 46
46
else
bs = b;
}
}
String ^ Description();
virtual double Perimeter() = 0;
virtual double Area() = 0;
CQuadrilateral();
};
CQuadrilateral::CQuadrilateral()
{
Name = L"Quadrilateral";
}
String ^ CQuadrilateral::Description()
{
return L"A quadrilateral is a geometric figure with four sides";
}
After creating an abstract class, even if you implement (some of) its properties and methods,
you cannot use the class. That is, you cannot declare a variable or handle of the class. This is
because the class is not complete. Remember that it has at least one method that is not
defined.
Deriving From an Abstract Class
Because an abstract class is not complete, you cannot (yet) use it. If you want to use
it, you must derive a class from it. If you decide to derive a class from an abstract one, you
must implement every one of its pure virtual methods in the new class. If you omit or forget
defining a pure virtual method, you would receive an error.
When declaring the pure virtual methods in the new class, replace the = 0 expression with the
override method. For the regular virtual properties or methods, you must flag them with
either the override or the new keyword. Here is an example of a class that derives from an
abstract class:
public ref class CSquare : public CQuadrilateral
{
public:
CSquare();
virtual String ^ Description() new;
virtual double Perimeter() override;
virtual double Area() override;
virtual void Display() override;
};
Page 47
47
Based on this, in the new class, define the pure virtual method(s) as you want. After defining
the new class, you can then instantiate it and use it as necessary. Here is an example:
using namespace System;
public ref class CQuadrilateral abstract
{
private:
double bs;
protected:
String ^ Name;
public:
virtual property double Base
{
double get() { return bs; }
void set(double b)
{
if( b <= 0 )
bs = 0.00;
else
bs = b;
}
}
virtual String ^ Description();
virtual double Perimeter() = 0;
virtual double Area() = 0;
virtual void Display() = 0;
CQuadrilateral();
};
CQuadrilateral::CQuadrilateral()
{
Name = L"Quadrilateral";
}
String ^ CQuadrilateral::Description()
{
return L"A quadrilateral is a geometric figure with four sides";
}
public ref class CSquare : public CQuadrilateral
{
public:
CSquare();
virtual String ^ Description() new;
virtual double Perimeter() override;
virtual double Area() override;
virtual void Display() override;
};
CSquare::CSquare()
{
Page 48
48
Name = L"Square";
}
String ^ CSquare::Description()
{
return L"A square is a quadrilateral with four equal sides";
}
double CSquare::Perimeter()
{
return 4 * Base;
}
double CSquare::Area()
{
return Base * Base;
}
void CSquare::Display()
{
Console::WriteLine(L" === Shape Properties ===");
Console::WriteLine(L"Name: {0}", Name);
Console::WriteLine(L"Description: {0}",
CQuadrilateral::Description());
Console::WriteLine(L" {0}", Description());
Console::WriteLine(L"Side: {0}", Base);
Console::WriteLine(L"Perimeter: {0}", Perimeter());
Console::WriteLine(L"Area: {0}", Area());
}
int main()
{
CSquare ^ sqr = gcnew CSquare;
sqr->Base = 22.46;
sqr->Display();
Console::WriteLine();
return 0;
}
This would produce:
=== Shape Properties ===
Name: Square
Description: A square is a quadrilateral with four equal sides
Side: 22.46
Perimeter: 89.84
Area: 504.4516
Press any key to continue . . .
Page 49
49
IV. POINTERS
Pointer is a variable which holds the memory address of another variable.
Reference operator (&)
As soon as we declare a variable, the amount of memory needed is assigned for it at a
specific location in memory (its memory address). We generally do not actively decide the
exact location of the variable within the panel of cells that we have imagined the memory to
be - Fortunately, that is a task automatically performed by the operating system during
runtime. However, in some cases we may be interested in knowing the address where our
variable is being stored during runtime in order to operate with relative positions to it.
The address that locates a variable within memory is what we call a reference to that
variable. This reference to a variable can be obtained by preceding the identifier of a variable
with an ampersand sign (&), known as reference operator, and which can be literally
translated as "address of". For example:
ted = &andy;
This would assign to ted the address of variable andy, since when preceding the name of the
variable andy with the reference operator (&) we are no longer talking about the content of
the variable itself, but about its reference (i.e., its address in memory).
From now on we are going to assume that andy is placed during runtime in the memory
address 1776. This number (1776) is just an arbitrary assumption we are inventing right now
in order to help clarify some concepts in this tutorial, but in reality, we cannot know before
runtime the real value the address of a variable will have in memory.
Consider the following code fragment:
andy = 25;
fred = andy;
ted = &andy;
The values contained in each variable after the execution of this, are shown in the following
diagram:
Page 50
50
First, we have assigned the value 25 to andy (a variable whose address in memory we have
assumed to be 1776).
The second statement copied to fred the content of variable andy (which is 25). This is a
standard assignment operation, as we have done so many times before.
Finally, the third statement copies to ted not the value contained in andy but a reference to it
(i.e., its address, which we have assumed to be 1776). The reason is that in this third
assignment operation we have preceded the identifier andy with the reference operator (&),
so we were no longer referring to the value of andy but to its reference (its address in
memory).
The variable that stores the reference to another variable (like ted in the previous example) is
what we call a pointer. Pointers are a very powerful feature of the C++ language that has
many uses in advanced programming. Farther ahead, we will see how this type of variable is
used and declared.
Dereference operator (*)
We have just seen that a variable which stores a reference to another variable is called a
pointer. Pointers are said to "point to" the variable whose reference they store.
Using a pointer we can directly access the value stored in the variable which it points to. To
do this, we simply have to precede the pointer's identifier with an asterisk (*), which acts as
dereference operator and that can be literally translated to "value pointed by".
Therefore, following with the values of the previous example, if we write:
beth = *ted;
Page 51
51
(that we could read as: "beth equal to value pointed by ted") beth would take the value 25,
since ted is 1776, and the value pointed by 1776 is 25.
You must clearly differentiate that the expression ted refers to the value 1776, while *ted
(with an asterisk * preceding the identifier) refers to the value stored at address 1776, which
in this case is 25. Notice the difference of including or not including the dereference operator
(I have included an explanatory commentary of how each of these two expressions could be
read):
beth = ted; // beth equal to ted ( 1776 )
beth = *ted; // beth equal to value pointed by ted ( 25 )
Notice the difference between the reference and dereference operators:
& is the reference operator and can be read as "address of"
* is the dereference operator and can be read as "value pointed by"
Thus, they have complementary (or opposite) meanings. A variable referenced with & can be
dereferenced with *.
Earlier we performed the following two assignment operations:
andy = 25;
ted = &andy;
Right after these two statements, all of the following expressions would give true as result:
andy == 25
&andy == 1776
ted == 1776
*ted == 25
Page 52
52
The first expression is quite clear considering that the assignment operation performed on
andy was andy=25. The second one uses the reference operator (&), which returns the
address of variable andy, which we assumed it to have a value of 1776. The third one is
somewhat obvious since the second expression was true and the assignment operation
performed on ted was ted=&andy. The fourth expression uses the dereference operator (*)
that, as we have just seen, can be read as "value pointed by", and the value pointed by ted is
indeed 25.
So, after all that, you may also infer that for as long as the address pointed by ted remains
unchanged the following expression will also be true:
*ted == andy
Declaring variables of pointer types
Due to the ability of a pointer to directly refer to the value that it points to, it becomes
necessary to specify in its declaration which data type a pointer is going point to. It is not the
same thing to point to a char than to point to an int or a float.
The declaration of pointers follows this format:
type * name;
where type is the data type of the value that the pointer is intended to point to. This type is
not the type of the pointer itself! but the type of the data the pointer points to. For example:
int * number;
char * character;
float * greatnumber;
These are three declarations of pointers. Each one is intended to point to a different data type,
but in fact all of them are pointers and all of them will occupy the same amount of space in
memory (the size in memory of a pointer depends on the platform where the code is going to
run). Nevertheless, the data to which they point to do not occupy the same amount of space
nor are of the same type: the first one points to an int, the second one to a char and the last
one to a float. Therefore, although these three example variables are all of them pointers
Page 53
53
which occupy the same size in memory, they are said to have different types: int*, char* and
float* respectively, depending on the type they point to.
I want to emphasize that the asterisk sign (*) that we use when declaring a pointer only
means that it is a pointer (it is part of its type compound specifier), and should not be
confused with the dereference operator that we have seen a bit earlier, but which is also
written with an asterisk (*). They are simply two different things represented with the same
sign.
Now have a look at this code:
// my first pointer
#include <iostream.H>
void main ()
{
int firstvalue, secondvalue;
int * mypointer;
mypointer = &firstvalue;
*mypointer = 10;
mypointer = &secondvalue;
*mypointer = 20;
cout << "firstvalue is " << firstvalue << endl;
cout << "secondvalue is " << secondvalue << endl;
}
Notice that even though we have never directly set a value to either firstvalue or secondvalue,
both end up with a value set indirectly through the use of mypointer. This is the procedure:
First, we have assigned as value of mypointer a reference to firstvalue using the reference
operator (&). And then we have assigned the value 10 to the memory location pointed by
mypointer, that because at this moment is pointing to the memory location of firstvalue, this
in fact modifies the value of firstvalue.
In order to demonstrate that a pointer may take several different values during the same
program I have repeated the process with secondvalue and that same pointer, mypointer.
Here is an example a little bit more elaborated:
// more pointers
#include <iostream.h>
void main ()
{
firstvalue is 10
secondvalue is
20
Page 54
54
int firstvalue = 5, secondvalue = 15;
int * p1, * p2;
p1 = &firstvalue; // p1 = address of firstvalue
p2 = &secondvalue; // p2 = address of secondvalue
*p1 = 10; // value pointed by p1 = 10
*p2 = *p1; // value pointed by p2 = value
pointed by p1
p1 = p2; // p1 = p2 (value of pointer is
copied)
*p1 = 20; // value pointed by p1 = 20
cout << "firstvalue is " << firstvalue << endl;
cout << "secondvalue is " << secondvalue << endl;
}
I have included as a comment on each line how the code can be read: ampersand (&) as
"address of" and asterisk (*) as "value pointed by".
Notice that there are expressions with pointers p1 and p2, both with and without dereference
operator (*). The meaning of an expression using the dereference operator (*) is very
different from one that does not: When this operator precedes the pointer name, the
expression refers to the value being pointed, while when a pointer name appears without this
operator, it refers to the value of the pointer itself (i.e. the address of what the pointer is
pointing to).
Another thing that may call your attention is the line:
int * p1, * p2;
This declares the two pointers used in the previous example. But notice that there is an
asterisk (*) for each pointer, in order for both to have type int* (pointer to int).
Otherwise, the type for the second variable declared in that line would have been int (and not
int*) because of precedence relationships. If we had written:
int * p1, p2;
p1 would indeed have int* type, but p2 would have type int (spaces do not matter at all for
this purpose). This is due to operator precedence rules. But anyway, simply remembering that
you have to put one asterisk per pointer is enough for most pointer users.
Page 55
55
Pointers and arrays
The concept of array is very much bound to the one of pointer. In fact, the identifier of an
array is equivalent to the address of its first element, as a pointer is equivalent to the address
of the first element that it points to, so in fact they are the same concept. For example,
supposing these two declarations:
int numbers [20];
int * p;
The following assignment operation would be valid:
p = numbers;
After that, p and numbers would be equivalent and would have the same properties. The only
difference is that we could change the value of pointer p by another one, whereas numbers
will always point to the first of the 20 elements of type int with which it was defined.
Therefore, unlike p, which is an ordinary pointer, numbers is an array, and an array can be
considered a constant pointer. Therefore, the following allocation would not be valid:
numbers = p;
Because numbers is an array, so it operates as a constant pointer, and we cannot assign values
to constants.
Due to the characteristics of variables, all expressions that include pointers in the following
example are perfectly valid:
// more pointers
#include <iostream>
using namespace std;
int main ()
{
int numbers[5];
int * p;
p = numbers; *p = 10;
p++; *p = 20;
p = &numbers[2]; *p = 30;
p = numbers + 3; *p = 40;
p = numbers; *(p+4) = 50;
for (int n=0; n<5; n++)
cout << numbers[n] << ", ";
return 0;
}
10, 20, 30, 40, 50,
Page 56
56
In the chapter about arrays we used brackets ([]) several times in order to specify the index of
an element of the array to which we wanted to refer. Well, these bracket sign operators [] are
also a dereference operator known as offset operator. They dereference the variable they
follow just as * does, but they also add the number between brackets to the address being
dereferenced. For example:
a[5] = 0; // a [offset of 5] = 0
*(a+5) = 0; // pointed by (a+5) = 0
These two expressions are equivalent and valid both if a is a pointer or if a is an array.
C++ array of pointers
Before we understand the concept of arrays of pointers, let us consider the following example
which makes use of an array of 3 integers:
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
for (int i = 0; i < MAX; i++)
{
cout << "Value of var[" << i << "] = ";
cout << var[i] << endl;
}
return 0;
}
When the above code is compiled and executed, it produces following result:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
There may be a situation when we want to maintain an array which can store pointers to an
int or char or any other data type available. Following is the declaration of an array of
pointers to an integer:
Page 57
57
int *ptr[MAX];
This declares ptr as an array of MAX integer pointers. Thus, each element in ptr, now holds a
pointer to an int value. Following example makes use of three integers which will be stored in
an array of pointers as follows:
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr[MAX];
for (int i = 0; i < MAX; i++)
{
ptr[i] = &var[i]; // assign the address of integer.
}
for (int i = 0; i < MAX; i++)
{
cout << "Value of var[" << i << "] = ";
cout << *ptr[i] << endl;
}
return 0;
}
When the above code is compiled and executed, it produces following result:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
Pointers and Strings
You can also use an array of pointers to character to store a list of strings as follows:
#include <iostream>
using namespace std;
const int MAX = 4;
int main ()
{
char *names[MAX] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali",
};
Page 58
58
for (int i = 0; i < MAX; i++)
{
cout << "Value of names[" << i << "] = ";
cout << names[i] << endl;
}
return 0;
}
When the above code is compiled and executed, it produces following result:
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali
Pointer initialization
When declaring pointers we may want to explicitly specify which variable we want them to
point to:
int number;
int *tommy = &number;
The behavior of this code is equivalent to:
int number;
int *tommy;
tommy = &number;
When a pointer initialization takes place we are always assigning the reference value to
where the pointer points (tommy), never the value being pointed (*tommy). You must
consider that at the moment of declaring a pointer, the asterisk (*) indicates only that it is a
pointer, it is not the dereference operator (although both use the same sign: *). Remember,
they are two different functions of one sign. Thus, we must take care not to confuse the
previous code with:
int number;
int *tommy;
*tommy = &number;
that is incorrect, and anyway would not have much sense in this case if you think about it.
Page 59
59
As in the case of arrays, the compiler allows the special case that we want to initialize the
content at which the pointer points with constants at the same moment the pointer is declared:
char * terry = "hello";
In this case, memory space is reserved to contain "hello" and then a pointer to the first
character of this memory block is assigned to terry. If we imagine that "hello" is stored at the
memory locations that start at addresses 1702, we can represent the previous declaration as:
It is important to indicate that terry contains the value 1702, and not 'h' nor "hello", although
1702 indeed is the address of both of these.
The pointer terry points to a sequence of characters and can be read as if it was an array
(remember that an array is just like a constant pointer). For example, we can access the fifth
element of the array with any of these two expressions:
*(terry+4)
terry[4]
Both expressions have a value of 'o' (the fifth element of the array).
How to Program C Pointers
Create your variable. Pointers are assigning variable address spaces. Therefore, before you
define a pointer, you need a variable. The code below shows you how to define a variable in
C:
int theInt = 0;
Define your pointer. Pointers are easily recognizable in your program, because it has an
asterisk prefix. The following code defines a pointer:
int *ptr;
Page 60
60
Assign the variable to the pointer. You assign the address space to the pointer, which is
accomplished using the ampersand symbol. Each time you see an ampersand prefix in C,
think "address of." The following code assigns the address of the integer to the pointer:
ptr = &theInt;
Since "theInt" is defined with a 0 value, the ptr variable contains the value of 0.
Change the value of the variable. Now that the pointer is assigned to the variable, changing
the pointer value changes the actual variable as well, The following code shows you how to
change variable values using a pointer:
*ptr = 5;
Print the results to view the value changes. This helps you learn and view the code
execution and how it affects pointers. The following code prints the results to your console:
theInt = 1;
printf("The value of theInt is %d", theInt); //prints out 5
*ptr = 10;
printf("The value of theInt is now %d", theInt); //prints out 10
Pointer arithmetic
To conduct arithmetical operations on pointers is a little different than to conduct
them on regular integer data types. To begin with, only addition and subtraction operations
are allowed to be conducted with them, the others make no sense in the world of pointers. But
both addition and subtraction have a different behavior with pointers according to the size of
the data type to which they point.
When we saw the different fundamental data types, we saw that some occupy more or less
space than others in the memory. For example, let's assume that in a given compiler for a
specific machine, char takes 1 byte, short takes 2 bytes and long takes 4.
Suppose that we define three pointers in this compiler:
char *mychar;
short *myshort;
long *mylong;
Page 61
61
and that we know that they point to memory locations 1000, 2000 and 3000 respectively.
So if we write:
mychar++;
myshort++;
mylong++;
mychar, as you may expect, would contain the value 1001. But not so obviously, myshort
would contain the value 2002, and mylong3004, even though they have each been increased
only once. The reason is that when adding one to a pointer we are making it to point to the
following element of the same type with which it has been defined, and therefore the size in
bytes of the type pointed is added to the pointer. would contain
This is applicable both when adding and subtracting any number to a pointer. It would
happen exactly the same if we write:
mychar = mychar + 1;
myshort = myshort + 1;
mylong = mylong + 1;
Both the increase (++) and decrease (--) operators have greater operator precedence than the
dereference operator (*), but both have a special behavior when used as suffix (the expression
is evaluated with the value it had before being increased). Therefore, the following
expression may lead to confusion:
*p++
Because ++ has greater precedence than *, this expression is equivalent to *(p++). Therefore,
what it does is to increase the value of p (so it now points to the next element), but because
Page 62
62
++ is used as postfix the whole expression is evaluated as the value pointed by the original
reference (the address the pointer pointed to before being increased).
Notice the difference with:
(*p)++
Here, the expression would have been evaluated as the value pointed by p increased by one.
The value of p (the pointer itself) would not be modified (what is being modified is what it is
being pointed to by this pointer).
If we write:
*p++ = *q++;
Because ++ has a higher precedence than *, both p and q are increased, but because both
increase operators (++) are used as postfix and not prefix, the value assigned to *p is *q
before both p and q are increased. And then both are increased. It would be roughly
equivalent to:
*p = *q;
++p;
++q;
Like always, I recommend you to use parentheses () in order to avoid unexpected results and
to give more legibility to the code.
Pointers to pointers
C++ allows the use of pointers that point to pointers, that these, in its turn, point to
data (or even to other pointers). In order to do that, we only need to add an asterisk (*) for
each level of reference in their declarations:
char a;
char * b;
char ** c;
a = 'z';
b = &a;
c = &b;
Page 63
63
This, supposing the randomly chosen memory locations for each variable of 7230, 8092 and
10502, could be represented as:
The value of each variable is written inside each cell; under the cells are their respective
addresses in memory.
The new thing in this example is variable c, which can be used in three different levels of
indirection, each one of them would correspond to a different value:
c has type char** and a value of 8092
*c has type char* and a value of 7230
**c has type char and a value of 'z'
void pointers
The void type of pointer is a special type of pointer. In C++, void represents the
absence of type, so void pointers are pointers that point to a value that has no type (and thus
also an undetermined length and undetermined dereference properties).
This allows void pointers to point to any data type, from an integer value or a float to a string
of characters. But in exchange they have a great limitation: the data pointed by them cannot
be directly dereferenced (which is logical, since we have no type to dereference to), and for
that reason we will always have to cast the address in the void pointer to some other pointer
type that points to a concrete data type before dereferencing it.
One of its uses may be to pass generic parameters to a function:
// increaser
#include <iostream>
using namespace std;
void increase (void* data, int psize)
{
if ( psize == sizeof(char) )
{ char* pchar; pchar=(char*)data; ++(*pchar); }
else if (psize == sizeof(int) )
{ int* pint; pint=(int*)data; ++(*pint); }
y, 1603
Page 64
64
}
int main ()
{
char a = 'x';
int b = 1602;
increase (&a,sizeof(a));
increase (&b,sizeof(b));
cout << a << ", " << b << endl;
return 0;
}
sizeof is an operator integrated in the C++ language that returns the size in bytes of its
parameter. For non-dynamic data types this value is a constant. Therefore, for example,
sizeof(char) is 1, because char type is one byte long.
Null pointer
A null pointer is a regular pointer of any pointer type which has a special value that
indicates that it is not pointing to any valid reference or memory address. This value is the
result of type-casting the integer value zero to any pointer type.
int * p;
p = 0; // p has a null pointer value
Do not confuse null pointers with void pointers. A null pointer is a value that any pointer may
take to represent that it is pointing to "nowhere", while a void pointer is a special type of
pointer that can point to somewhere without a specific type. One refers to the value stored in
the pointer itself and the other to the type of data it points to.
Pointers to functions
C++ allows operations with pointers to functions. The typical use of this is for passing
a function as an argument to another function, since these cannot be passed dereferenced. In
order to declare a pointer to a function we have to declare it like the prototype of the function
except that the name of the function is enclosed between parentheses () and an asterisk (*) is
inserted before the name:
// pointer to functions
#include <iostream>
using namespace std;
Page 65
65
int addition (int a, int b)
{ return (a+b); }
int subtraction (int a, int b)
{ return (a-b); }
int operation (int x, int y, int (*functocall)(int,int))
{
int g;
g = (*functocall)(x,y);
return (g);
}
int main ()
{
int m,n;
int (*minus)(int,int) = subtraction;
m = operation (7, 5, addition);
n = operation (20, m, minus);
cout <<n;
return 0;
}
In the example, minus is a pointer to a function that has two parameters of type int. It is
immediately assigned to point to the function subtraction, all in a single line:
int (* minus)(int,int) = subtraction;
Pointers to Objects
#include <iostream>
using namespace std;
class myclass {
int i;
public:
myclass(int j) {
i = j;
}
int getInt() {
return i;
}
};
int main()
{
myclass ob(88), *objectPointer;
objectPointer = &ob; // get address of ob
cout << objectPointer->getInt(); // use -> to call getInt()
return 0;
}
Page 66
66
this Pointer
The this pointer is a pointer accessible only within the nonstatic member functions of
a class, struct, or union type. It points to the object for which the member function is called.
Static member functions do not have a this pointer.
this
this->member-identifier
Remarks
An object's this pointer is not part of the object itself; it is not reflected in the result of a
sizeof statement on the object. Instead, when a nonstatic member function is called for an
object, the address of the object is passed by the compiler as a hidden argument to the
function. For example, the following function call:
myDate.setMonth( 3 );
can be interpreted this way:
setMonth( &myDate, 3 );
The object's address is available from within the member function as the this pointer. Most
uses of this are implicit. It is legal, though unnecessary, to explicitly use this when referring
to members of the class. For example:
void Date::setMonth( int mn )
{
month = mn; // These three statements
this->month = mn; // are equivalent
(*this).month = mn;
}
The expression *this is commonly used to return the current object from a member function:
return *this;
The this pointer is also used to guard against self-reference:
if (&Object != this) {
// do not execute in cases of self-reference
Note
Because the this pointer is non modifiable, assignments to this are not allowed. Earlier
implementations of C++ allowed assignments to this.
Page 67
67
Occasionally, the this pointer is used directly — for example, to manipulate self-referential
data structures, where the address of the current object is required.
Example
// this_pointer.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h>
using namespace std;
class Buf
{
public:
Buf( char* szBuffer, size_t sizeOfBuffer );
Buf& operator=( const Buf & );
void Display() { cout << buffer << endl; }
private:
char* buffer;
size_t sizeOfBuffer;
};
Buf::Buf( char* szBuffer, size_t sizeOfBuffer )
{
sizeOfBuffer++; // account for a NULL terminator
buffer = new char[ sizeOfBuffer ];
if (buffer)
{
strcpy_s( buffer, sizeOfBuffer, szBuffer );
sizeOfBuffer = sizeOfBuffer;
}
}
Buf& Buf::operator=( const Buf &otherbuf )
{
if( &otherbuf != this )
{
if (buffer)
delete [] buffer;
sizeOfBuffer = strlen( otherbuf.buffer ) + 1;
buffer = new char[sizeOfBuffer];
strcpy_s( buffer, sizeOfBuffer, otherbuf.buffer );
}
return *this;
}
int main()
{
Buf myBuf( "my buffer", 10 );
Buf yourBuf( "your buffer", 12 );
// Display 'my buffer'
myBuf.Display();
Page 68
68
// assignment opperator
myBuf = yourBuf;
// Display 'your buffer'
myBuf.Display();
}
Output
my buffer
your buffer