members this - sri venkateswara college of engineering · programming and data structures ii –...

84
Programming and Data Structures II – Unit 1 UNIT – I Object Oriented Programming Fundamentals C++ Programming features - Data Abstraction - Encapsulation - class - object - constructors - static members – constant members – member functions – pointers – references - Role of this pointer – Storage classes – function as arguments SESSION - 1 Introduction The core of the pure object-oriented programming is to create an object, in code, that has certain properties and methods. While designing C++ modules, we try to see whole world in the form of objects. For example a car is an object which has certain properties such as color, number of doors, and the like. It also has certain methods such as accelerate, brake, and so on. C++ supports a variety of programming Style. All are based on strong static type checking, and most aim at achieving a high level of abstraction and a direct representation of the programmer’s ideas. Each style can achieve its aims effectively while maintaining run-time and space efficiency. C++ has no built-in high-level data types and no high-level primitive operations. For example, the C++ language does not provide a matrix type with an inversion operator or a string type with a concatenation operator. If a user wants such a type, it can be defined in the language itself. In fact, defining a new general-purpose or application-specific type is the most fundamental programming activity in C++. C++ type-checking and data-hiding features rely on compile-time analysis of programs to prevent accidental corruption of data. They do not provide secrecy or protection against someone who is deliberately breaking the rules. They can, however, be used freely without incurring run-time or space overheads. The idea is that to be useful, a language feature must not only be elegant; it must also be affordable in the context of a real program.

Upload: vuongquynh

Post on 10-Apr-2018

215 views

Category:

Documents


2 download

TRANSCRIPT

Programming and Data Structures II – Unit 1

UNIT – I Object Oriented Programming Fundamentals

C++ Programming features - Data Abstraction - Encapsulation - class - object - constructors - static

members – constant members – member functions – pointers – references - Role of this pointer –

Storage classes – function as arguments

SESSION - 1

Introduction

The core of the pure object-oriented programming is to create an object, in code, that has

certain properties and methods. While designing C++ modules, we try to see whole world in the

form of objects. For example a car is an object which has certain properties such as color, number

of doors, and the like. It also has certain methods such as accelerate, brake, and so on.

C++ supports a variety of programming Style. All are based on strong static type checking,

and most aim at achieving a high level of abstraction and a direct representation of the

programmer’s ideas. Each style can achieve its aims effectively while maintaining run-time and

space efficiency.

C++ has no built-in high-level data types and no high-level primitive operations. For

example, the C++ language does not provide a matrix type with an inversion operator or a string

type with a concatenation operator. If a user wants such a type, it can be defined in the language

itself. In fact, defining a new general-purpose or application-specific type is the most fundamental

programming activity in C++.

C++ type-checking and data-hiding features rely on compile-time analysis of programs to

prevent accidental corruption of data. They do not provide secrecy or protection against someone

who is deliberately breaking the rules. They can, however, be used freely without incurring run-time

or space overheads. The idea is that to be useful, a language feature must not only be elegant; it

must also be affordable in the context of a real program.

Programming and Data Structures II – Unit 1

Difference between C and C++

S.No C C++

1 C is expressive and permissive C++ is even more expressive. - to gain that

increase in expressiveness, you must pay

more attention to the types of objects.

2 Lines of Code is less than C++ The aim was to have an average line of C++

code express much more than the average line

of C or Pascal code.

3 C follows the procedural programming

paradigm

C++ is a multi-paradigm language(procedural

as well as object oriented)

4 In case of C, the data is not secured The data is secured(hidden) in C++

This difference is due to specific OOP

features like Data Hiding which are not

present in C.

5 C is a low-level language C++ is a middle-level language. C++ has

features of both low-level(concentration on

whats going on in the machine hardware) &

high-level languages(concentration on the

program itself) & hence is regarded as a

middle-level language.

6 C uses the top-down approach - In case

of C, the program is formulated step by

step, each step is processed into detail

C++ uses the bottom-up approach - in C++,

the base elements are first formulated which

then are linked together to give rise to larger

systems.

7 C is function-driven - Functions are the

building blocks of a C program

C++ is object-driven - Objects are building

blocks of a C++ program.

8 C does not support function overloading C++ supports function overloading.

Overloading means two functions having the

Programming and Data Structures II – Unit 1

same name in the same program. This can be

done only in C++ with the help of

Polymorphism(an OOP feature)

9 We can not use functions inside

structures in C

In case of C++, functions can be used

inside a structure

10 NAMESPACE is absent in case of C C++ uses NAMESPACE which avoid

name collisions

11 C does not support Exception Handling C++ supports Exception Handling

Advantages of C++

• C++ was designed to enable larger programs to be structured in a rational way so that it would be reasonable

for a single person to cope with far larger amounts of code.

• C++’s emphasis on modularity, strongly typed interfaces, and flexibility

• A C++ program declaring function argument types, using classes

C++ Programming Features:

C++ introduces object-oriented programming (OOP) features to C. It offers classes, which

provide the four features commonly present in OOP (and some non-OOP) languages: abstraction,

encapsulation, inheritance, and polymorphism. One distinguishing feature of C++ classes compared

to classes in other programming languages is support for deterministic destructors, which in turn

provide support for the Resource Acquisition is Initialization (RAII) concept.

Data Abstraction

Data abstraction refers to, providing only essential information to the outside world and

hiding their background details, i.e., to represent the needed information in program without

presenting the details.

Data abstraction is a programming (and design) technique that relies on the separation of

interface and implementation.

A programmer can partition an application into manageable pieces by defining new types

that closely match the concepts of the application. This technique for program construction is often

called data abstraction.

Programming and Data Structures II – Unit 1

Let's take one real life example of a TV, which you can turn on and off, change the channel, adjust

the volume, and add external components such as speakers, VCRs, and DVD players, BUT you do

not know its internal details, that is, you do not know how it receives signals over the air or through

a cable, how it translates them, and finally displays them on the screen.

Thus, we can say a television clearly separates its internal implementation from its external

interface and you can play with its interfaces like the power button, channel changer, and volume

control without having zero knowledge of its internals.

Now, if we talk in terms of C++ Programming, C++ classes provides great level of data

abstraction. They provide sufficient public methods to the outside world to play with the

functionality of the object and to manipulate object data, i.e., state without actually knowing how

class has been implemented internally.

For example, your program can make a call to the sort() function without knowing what algorithm

the function actually uses to sort the given values. In fact, the underlying implementation of the

sorting functionality could change between releases of the library, and as long as the interface stays

the same, your function call will still work.

In C++, we use classes to define our own abstract data types (ADT). You can use the cout object of

class ostream to stream data to standard output like this:

#include <iostream>

using namespace std;

int main( )

{

cout << "Hello C++" <<endl;

return 0;

}

Here, you don't need to understand how cout displays the text on the user's screen. You need to only

know the public interface and the underlying implementation of cout is free to change.

Access Labels Enforce Abstraction:

In C++, we use access labels to define the abstract interface to the class. A class may contain zero or

more access labels:

Programming and Data Structures II – Unit 1

• Members defined with a public label are accessible to all parts of the program. The data-

abstraction view of a type is defined by its public members.

• Members defined with a private label are not accessible to code that uses the class. The

private sections hide the implementation from code that uses the type.

There are no restrictions on how often an access label may appear. Each access label specifies the

access level of the succeeding member definitions. The specified access level remains in effect until

the next access label is encountered or the closing right brace of the class body is seen.

Benefits of Data Abstraction:

Data abstraction provides two important advantages:

• Class internals are protected from inadvertent user-level errors, which might corrupt the

state of the object.

• The class implementation may evolve over time in response to changing requirements or

bug reports without requiring change in user-level code.

By defining data members only in the private section of the class, the class author is free to make

changes in the data. If the implementation changes, only the class code needs to be examined to see

what affect the change may have. If data are public, then any function that directly accesses the data

members of the old representation might be broken.

Data Abstraction Example:

Any C++ program where you implement a class with public and private members is an example of

data abstraction. Consider the following example:

#include <iostream>

using namespace std;

class Adder{

public:

// constructor

Adder(int i = 0)

{

total = i;

Programming and Data Structures II – Unit 1

}

// interface to outside world

void addNum(int number)

{

total += number;

}

// interface to outside world

int getTotal()

{

return total;

};

private:

// hidden data from outside world

int total;

};

int main( )

{

Adder a;

a.addNum(10);

a.addNum(20);

a.addNum(30);

cout << "Total " << a.getTotal() <<endl;

return 0;

}

When the above code is compiled and executed, it produces the following result:

Total 60

Above class adds numbers together, and returns the sum. The public members addNum and

getTotal are the interfaces to the outside world and a user needs to know them to use the class. The

private member total is something that the user doesn't need to know about, but is needed for the

class to operate properly.

Programming and Data Structures II – Unit 1

Encapsulation

Encapsulation is the hiding of information to ensure that data structures and operators are used as

intended and to make the usage model more obvious to the developer. C++ provides the ability to

define classes and functions as its primary encapsulation mechanisms. Within a class, members can

be declared as either public, protected, or private to explicitly enforce encapsulation. A public

member of the class is accessible to any function. A private member is accessible only to functions

that are members of that class and to functions and classes explicitly granted access permission by

the class ("friends"). A protected member is accessible to members of classes that inherit from the

class in addition to the class itself and any friends.

The OO principle is that all of the functions (and only the functions) that access the internal

representation of a type should be encapsulated within the type definition. C++ supports this (via

member functions and friend functions), but does not enforce it: the programmer can declare parts

or all of the representation of a type to be public, and is allowed to make public entities that are not

part of the representation of the type. Therefore, C++ supports not just OO programming, but other

weaker decomposition paradigms, like modular programming.

It is generally considered good practice to make all data private or protected, and to make public

only those functions that are part of a minimal interface for users of the class. This can hide the

details of data implementation, allowing the designer to later fundamentally change the

implementation without changing the interface in any way.

Designing Strategy:

Abstraction separates code into interface and implementation. So while designing your component,

you must keep interface independent of the implementation so that if you change underlying

implementation then interface would remain intact.

In this case whatever programs are using these interfaces, they would not be impacted and would

just need a recompilation with the latest implementation.

Data encapsulation

All C++ programs are composed of the following two fundamental elements:

• Program statements (code): This is the part of a program that performs actions and they

are called functions.

Programming and Data Structures II – Unit 1

• Program data: The data is the information of the program which affected by the program

functions.

Encapsulation is an Object Oriented Programming concept that binds together the data and

functions that manipulate the data, and that keeps both safe from outside interference and misuse.

Data encapsulation led to the important OOP concept of data hiding.

Data encapsulation is a mechanism of bundling the data, and the functions that use them and data

abstraction is a mechanism of exposing only the interfaces and hiding the implementation details

from the user.

C++ supports the properties of encapsulation and data hiding through the creation of user-defined

types, called classes. We already have studied that a class can contain private, protected and

public members. By default, all items defined in a class are private. For example:

class Box

{

public:

double getVolume(void)

{

return length * breadth * height;

}

private:

double length; // Length of a box

double breadth; // Breadth of a box

double height; // Height of a box

};

The variables length, breadth, and height are private. This means that they can be accessed only by

other members of the Box class, and not by any other part of your program. This is one way

encapsulation is achieved.

To make parts of a class public (i.e., accessible to other parts of your program), you must declare

them after the public keyword. All variables or functions defined after the public specifier are

accessible by all other functions in your program.

Making one class a friend of another exposes the implementation details and reduces encapsulation.

The ideal is to keep as many of the details of each class hidden from all other classes as possible.

Programming and Data Structures II – Unit 1

Data Encapsulation Example:

Any C++ program where you implement a class with public and private members is an example of

data encapsulation and data abstraction. Consider the following example:

#include <iostream>

using namespace std;

class Adder{

public:

// constructor

Adder(int i = 0)

{

total = i;

}

// interface to outside world

void addNum(int number)

{

total += number;

}

// interface to outside world

int getTotal()

{

return total;

};

private:

// hidden data from outside world

int total;

};

int main( )

{

Adder a;

a.addNum(10);

a.addNum(20);

Programming and Data Structures II – Unit 1

a.addNum(30);

cout << "Total " << a.getTotal() <<endl;

return 0;

}

When the above code is compiled and executed, it produces the following result:

Total 60

Above class adds numbers together, and returns the sum. The public members addNum and

getTotal are the interfaces to the outside world and a user needs to know them to use the class. The

private member total is something that is hidden from the outside world, but is needed for the class

to operate properly.

Designing Strategy:

Most of us have learned through bitter experience to make class members private by default unless

we really need to expose them. That's just good encapsulation.

This wisdom is applied most frequently to data members, but it applies equally to all members,

including virtual functions.

Inheritance

Inheritance allows one data type to acquire properties of other data types. Inheritance from a base

class may be declared as public, protected, or private. This access specifier determines whether

unrelated and derived classes can access the inherited public and protected members of the base

class. Only public inheritance corresponds to what is usually meant by "inheritance". The other two

forms are much less frequently used. If the access specifier is omitted, a "class" inherits privately,

while a "struct" inherits publicly. Base classes may be declared as virtual; this is called virtual

inheritance. Virtual inheritance ensures that only one instance of a base class exists in the

inheritance graph, avoiding some of the ambiguity problems of multiple inheritance.

Polymorphism

It enables one common interface for many implementations, and for objects to act differently

under different circumstances.Polymorphism refers to a single function or multi-functioning

Programming and Data Structures II – Unit 1

operator performing in different ways. C++ supports several kinds of static (compile-time) and

dynamic (run-time) polymorphisms.

Overloading

Overloading is one type of Polymorphism. It allows an object to have different meanings,

depending on its context. When an exiting operator or function begins to operate on new data type,

or class, it is understood to be overloaded. Overloading is the reuse of the same symbol or function

name for two or more distinct operations or functions. Overloading can be used with operators and

functions.

Reusability:

This term refers to the ability for multiple programmers to use the same written and

debugged existing class of data. This is a time saving device and adds code efficiency to the

language. Additionally, the programmer can incorporate new features to the existing class, further

developing the application and allowing users to achieve increased performance. This time saving

feature optimizes code, helps in gaining secured applications and facilitates easier maintenance on

the application

The implementation of each of the above object-oriented programming features for C++ will be

highlighted in later sections

Programming and Data Structures II – Unit 1

Session 2

Class

The key concept in C++ is class. A class is a userdefined type. Classes provide data hiding,

guaranteed initialization of data, implicit type conversion for user defined types, dynamic typing,

usercontrolled memory management, and mechanisms for overloading operators.

A C++ class is a type. That is, it specifies how objects of its class behave: how they are

created, how they can be manipulated, and how they are destroyed. A class may also specify how

objects are represented, although in the early stages of the design of a program that should not be

the major concern. The key to writing good programs is to design classes so that each cleanly

represents a single concept. When you define Class, it should define “How are objects of this class

created?” , “Can objects of this class be copied and/or destroyed?” , “ What operations can be

applied to such objects?”. It might then be a good idea to think more about the problem and its

proposed solution instead of immediately starting to ‘‘code around’’ the problems

A class definition starts with the keyword class followed by the class name; and the class

body, enclosed by a pair of curly braces. A class definition must be followed either by a semicolon

or a list of declarations. For example, we defined the Box data type using the keyword class as

follows:

Encapsulation of type and related operations

class point {

double x,y; // private data members

public:

point (int x0, int y0); // public methods

point () { x = 0; y = 0;}; // a constructor

void move (int dx, int dy);

void rotate (double alpha);

int distance (point p);

}

The keyword public determines the access attributes of the members of the class that follow

Programming and Data Structures II – Unit 1

it. A public member can be accessed from outside the class anywhere within the scope of the class

object. The data and functions within a class are called members of the class.

A method (member function) is a function contained within the class. You will find the

functions used within a class often referred to as methods in programming literature.

A message is the same thing as a function call. In object oriented programming, we send

messages instead of calling functions.

Classes include both data and the functions involved with these data (encapsulation).

How to access Data members?

The public data members of objects of a class can be accessed using the direct member access

operator (.). Let us try the following example to make the things clear:

#include <iostream>

using namespace std;

class Box

{

public:

double length; // Length of a box

double breadth; // Breadth of a box

double height; // Height of a box

};

int main( )

{

Box Box1; // Declare Box1 of type Box

Box Box2; // Declare Box2 of type Box

double volume = 0.0; // Store the volume of a box here

// box 1 specification

Box1.height = 5.0;

Box1.length = 6.0;

Box1.breadth = 7.0;

// box 2 specification

Programming and Data Structures II – Unit 1

Box2.height = 10.0;

Box2.length = 12.0;

Box2.breadth = 13.0;

// volume of box 1

volume = Box1.height * Box1.length * Box1.breadth;

cout << "Volume of Box1 : " << volume <<endl;

// volume of box 2

volume = Box2.height * Box2.length * Box2.breadth;

cout << "Volume of Box2 : " << volume <<endl;

return 0;

}

When the above code is compiled and executed, it produces the following result:

Volume of Box1 : 210

Volume of Box2 : 1560

It is important to note that private and protected members can not be accessed directly using

direct member access operator (.). We will learn how private and protected members can be

accessed.

Member access specifiers:

Access specifiers are used to identify access rights for the data and member functions of the

class. There are three main types of access specifiers in C++ programming language:

• private

• public

• protected

➔ A private member within a class denotes that only members of the same class have accessibility.

The private member is inaccessible from outside the class. By default, members would be

assumed as private.

➔ Public members are accessible from outside the class.

➔ A protected access specifier is used only by the members and friends of class and the members

and friends of classes derived from class.

Programming and Data Structures II – Unit 1

/* C++ Program to Illustrate the use of Access Control Specifiers */

#include <iostream>

class Base {

private:

int a;

protected:

int b;

public:

int c;

Base(int aa = 1, int bb = 2, int cc = 3) : a(aa), b(bb), c(cc) {}

virtual ~Base() {}

};

class Derived: public Base {

int j;

public:

Derived(int jj = 0) : j(jj) {}

void change()

{

// 'b' is protected

j = b;

}

void printValue()

Programming and Data Structures II – Unit 1

{

std::cout << "Derived::j = " << j

<< std::endl;

}

};

int main()

{

Base base;

Derived derived;

// 'a' and 'b' are private and protected

// std::cout << base.a << std::endl;

// std::cout << base.b << std::endl;

std::cout << "Base::c = "<< base.c << std::endl;

derived.change();

derived.printValue();

}

Output:

Base::c = 3

Derived::j = 2

Object

Objects, which are usually instances of classes, are used to interact with one another to

design applications and computer programs.Many real-world objects have both a state

(characteristics that can change) and abilities (things they can do).

Real-world object=State (properties)+ Abilities (behavior)

Programming and Data Structures II – Unit 1

Programming objects = Data + Functions

The match between programming objects and real-world objects is the result of combining

data and member functions.

Objects can be created in several ways. Some are local variables, some are global variables,

some are members of classes, etc.

Creation of Objects:

Once the class is created, one or more objects can be created from the class as objects are

instance of the class. Objects are also declared as:

class name followed by object name;

sample e1; - This declares e1 to be an object of class sample.

For example a complete class and object declaration is given below:

class sample

{

private:

int x,y;

public:

void sum()

{

………

………

}

};

main()

{

sample e1;

Programming and Data Structures II – Unit 1

……………

……………

}

Session 3

Constructors

Constructor is a specialised method that is contained in the class. Constructor will be

triggered automaticallywhen an object is created. Purpose of the constructor is to initialize an object

of a class.

Constructor name is identical to the class name. Constructors can take parameters but

constructirs have no return type. This is because constructors return an object by itself.

What is the use of Constructor

The main use of constructors is to initialize objects. The function of initialization is automatically

carried out by the use of a special member function called a constructor.

General Syntax of Constructor

Constructor is a special member function that takes the same name as the class name. The syntax

generally is as given below:

<class name> { arguments};

The default constructor for a class X has the form

X::X()

In the above example the arguments is optional. The constructor is automatically invoked when an

object is created.

The various types of constructors are

Default constructors

Parameterized constructors

Copy constructors

1. Default Constructor:- Default Constructor is also called as Empty Constructor which has no

arguments or all the parameters have default values. If no constructors are available for a class, the

compiler implicitly creates a default parameterless constructor without a constructor initializer and a

Programming and Data Structures II – Unit 1

null body.

It is Automatically called when we creates the object of class but Remember name of Constructor

is same as name of class and Constructor never declared with the help of Return Type. Means we

cant Declare a Constructor with the help of void Return Type. , if we never Pass or Declare any

Arguments then this called as the Copy Constructors.

Example:

#include <iostream.h>

class Defal

{

public:

int x;

int y;

Defal(){x=y=0;}

};

int main()

{

Defal A;

cout << "Default constructs x,y value::"<<

A.x <<" , "<< A.y << "\n";

return 0;

}

RESULT:

Default constructs x,y value:: 0,0

In the above example a default constructor has the default value of "0" for both the parameters.

2.Parameterized Constructor :- This is Another type Constructor which has some Arguments and

same name as class name but it uses some Arguments So For this We have to create object of Class

by passing some Arguments at the time of creating object with the name of class. When we pass

some Arguments to the Constructor then this will automatically pass the Arguments to the

Constructor and the values will retrieve by the Respective Data Members of the Class.

Programming and Data Structures II – Unit 1

/*PROGRAM TO IMPLEMENT PARAMETERIZED CONSTRUCTOR*/

#include<iostream.h>

#include<conio.h>

class area

{

int length,breadth;

public:

area(int l,int b)

{

length=l;

breadth=b;

cout<<”Length of rectangle is:”<<length<<endl;

cout<<”Breadth of rectangle is: “<<breadth<<endl;

}

void display()

{

cout<<”Area of rectangle is: “<<length*breadth;

}

};

void main()

{

clrscr();

area a1(8,7);

a1.display();

getch();

}

Programming and Data Structures II – Unit 1

Result:

Length of rectangle is:7

Breadth of rectangle is:

Area of rectangle is: 56

3.Copy Constructor:- This is also Another type of Constructor. In this Constructor we pass the

object of class into the Another Object of Same Class. As name Suggests you Copy, means Copy

the values of one Object into the another Object of Class .This is used for Copying the values of

class object into an another object of class So we call them as Copy Constructor and For Copying

the values We have to pass the name of object whose values we wants to Copying and When we are

using or passing an Object to a Constructor then we must have to use the & Ampersand or Address

Operator.

Normally the compiler automatically creates a copy constructor for each class (known as a default

copy constructor) but for special cases the programmer creates the copy constructor, known as a

user-defined copy constructor. In such cases, the compiler does not create one.

A user-defined copy constructor is generally needed when an object owns pointers or non-shareable

references, such as to a file, in which case a destructor and an assignment operator should also be

written (see Rule of three).

Definition

Copying of objects is achieved by the use of a copy constructor and a assignment operator. A

copy constructor has as its first parameter a (possibly const or volatile) reference to its own class

type. It can have more arguments, but the rest must have default values associated with them.

Syntax:

Class::Class(const Class&);

The following would be valid copy constructors for class X:

Programming and Data Structures II – Unit 1

X(const X& copyFromMe);

X(X& copyFromMe);

X(const volatile X& copyFromMe);

X(volatile X& copyFromMe);

X(const X& copyFromMe, int = 10);

X(const X& copyFromMe, double = 1.0, int = 40);

The first one should be used unless there is a good reason to use one of the others. One of the

differences between the first and the second is that temporaries can be copied with the first. For

example:

X a = X(); // valid if you have X(const X& copyFromMe) but not valid if you have X(X&

copyFromMe)

// because the second wants a non-const X&

// to create a, the compiler first creates a temporary by invoking the default constructor

// of X, then uses the copy constructor to initialize a as a copy of that temporary.

// However, for some compilers both the first and the second actually work.

Another difference between them is the obvious:

X const a;

X b = a; // valid if you have X(X const& copyFromMe) but not valid if you have X(X&

copyFromMe)

// because the second wants a non-const X&

The X& form of the copy constructor is used when it is necessary to modify the copied object. This

is very rare but it can be seen used in the standard library's std::auto_ptr. A reference must be

provided:

X a;

X b = a; // valid if any of the copy constructors is defined

// since you're passing in a reference

The following are invalid copy constructors (Reason - copyFromMe is not passed as reference) :

X(X copyFromMe);

Programming and Data Structures II – Unit 1

X(const X copyFromMe);

because the call to those constructors would require a copy as well, which would result in an

infinitely recursive call.

The following cases may result in a call to a copy constructor:

1. When an object is returned by value

2. When an object is passed (to a function) by value as an argument

3. When an object is thrown

4. When an object is caught

5. When an object is placed in a brace-enclosed initializer list

These cases are collectively called copy-initialization and are equivalent to:[2] T x = a;

It is however, not guaranteed that a copy constructor will be called in these cases, because the C++

Standard allows the compiler to optimize the copy away in certain cases, one example being the

return value optimization (sometimes referred to as RVO).

Explicit assignment in an expression

Object A;

Object B;

A = B; // translates as Object::operator=(const Object&), thus A.operator=(B) is called

// (invoke simple copy, not copy constructor!)

Initialization

An object can be initialized by any one of the following ways.

a. Through declaration

Object B = A; // translates as Object::Object(const Object&) (invoke copy constructor)

Programming and Data Structures II – Unit 1

b. Through function arguments

type function (Object a);

c. Through function return value

Object a = function();

The copy constructor is used only for initializations, and does not apply to assignments

where the assignment operator is used instead.

The implicit copy constructor of a class calls base copy constructors and copies its members

by means appropriate to their type. If it is a class type, the copy constructor is called. If it is a scalar

type, the built-in assignment operator is used. Finally, if it is an array, each element is copied in the

manner appropriate to its type.

By using a user-defined copy constructor the programmer can define the behavior to be

performed when an object is copied.

Implicit copy constructor

Let us consider the following example.

//copy constructor

#include <iostream>

class Person

{

public:

int age;

explicit Person(int age)

: age(age) {}

};

Programming and Data Structures II – Unit 1

int main()

{

Person timmy(10);

Person sally(15);

Person timmy_clone = timmy;

std::cout << timmy.age << " " << sally.age << " " << timmy_clone.age << std::endl;

timmy.age = 23;

std::cout << timmy.age << " " << sally.age << " " << timmy_clone.age << std::endl;

return 0;

}

Output

10 15 10

23 15 10

As expected, timmy has been copied to the new object, timmy_clone. While timmy's age was

changed, timmy_clone's age remained the same. This is because they are totally different objects.

The compiler has generated a copy constructor for us, and it could be written like this:

Person(const Person& copy)

: age(copy.age) {}

So, when do we really need a user-defined copy constructor? The next section will explore that

question.

Programming and Data Structures II – Unit 1

User-defined copy constructor

Now, consider a very simple dynamic array class like the following:

#include <iostream>

class Array

{

public:

int size;

int* data;

explicit Array(int size)

: size(size), data(new int[size]) {}

~Array()

{

delete[] data;

}

};

int main()

{

Array first(20);

first.data[0] = 25;

{

Array copy = first;

std::cout << first.data[0] << " " << copy.data[0] << std::endl;

} // (1)

first.data[0] = 10; // (2)

Programming and Data Structures II – Unit 1

return 0;

}

Output

25 25

Segmentation fault

For example to invoke a copy constructor the programmer writes:

Exforsys e3(e2);

or

Exforsys e3=e2;

Both the above formats can be sued to invoke a copy constructor

Example

#include <iostream.h>

class Exforsys()

{

private:

int a;

public:

Exforsys()

{ }

Exforsys(int w)

{

a=w;

}

Exforsys(Exforsys& e)

Programming and Data Structures II – Unit 1

{

a=e.a;

cout<<” Example of Copy Constructor”;

}

void result()

{

cout<< a;

}

};

void main()

{

Exforsys e1(50);

Exforsys e3(e1);

cout<< “\ne3=”;e3.result();

}

In the above the copy constructor takes one argument an object of type Exforsys which is passed by

reference. The output of the above program is

Example of Copy Constructor

e3=50

Example:

Class rectangle {

private:

float height;

float width;

int xpos;

int ypos;

Programming and Data Structures II – Unit 1

public:

rectangle(float, float); // constructor

rectangle(const rectangle&); // copy constructor

void draw(); // draw member function

void posn(int, int); // position member function

void move(int, int); // move member function

};

rectangle::rectangle(const rectangle& old_rc)

{

height = old_rc.height;

width = old_rc.width;

xpos = old_rc.xpos;

ypos = old_rc.ypos;

}

void main()

{

rectangle rc1(3.0, 2.0); // use constructor

rectangle rc2(rc1); // use copy constructor

rectangle rc3 = rc1; // alternative syntax for

}

difference between copy constructor and constructor

• Constructor is called when an object is created.Copy constructor is called when the

copy of an object is made. For e.g. passing parameter to function by value function

returning by value. Copy constructor takes the parameter as const reference to the

object.

• A copy constructor is called whenever an object is passed by value, returned by value

Programming and Data Structures II – Unit 1

or explicitly copied. statements;

Destructors

The destructor of an automatic object is called when the object goes out of scope. The destructor

itself does not actually destroy the object, but it does perform termination housekeeping before the

system reclaims the object‘s.

What is the use of Destructors

Destructors are also special member functions used in C++ programming language.

Destructors have the opposite function of a constructor. The main use of destructors is to release

dynamic allocated memory. Destructors are used to free memory, release resources and to perform

other clean up. Destructors are automatically named when an object is destroyed. Like constructors,

destructors also take the same name as that of the class name.

General Syntax of Destructors

~ classname();

The above is the general syntax of a destructor. In the above, the symbol tilda ~ represents a

destructor which precedes the name of the class.

Some important points about destructors:

• Destructors take the same name as the class name.

• Like the constructor, the destructor must also be defined in the public. The destructor must

be a public member.

• The Destructor does not take any argument which means that destructors cannot be

overloaded.

• No return type is specified for destructors.

Iclass X {

public:

// Constructor for class X

X();

Programming and Data Structures II – Unit 1

// Destructor for class X

~X();

};

A destructor takes no arguments and has no return type. Its address cannot be taken. Destructors

cannot be declared const, volatile, const volatile or static. A destructor can be declared virtual or

pure virtual.

If no user-defined destructor exists for a class and one is needed, the compiler implicitly declares a

destructor. This implicitly declared destructor is an inline public member of its class.

The compiler will implicitly define an implicitly declared destructor when the compiler uses the

destructor to destroy an object of the destructor's class type. Suppose a class A has an implicitly

declared destructor. The following is equivalent to the function the compiler would implicitly define

for A:

A::~A() { }

The compiler first implicitly defines the implicitly declared destructors of the base classes and

nonstatic data members of a class A before defining the implicitly declared destructor of A

A destructor of a class A is trivial if all the following are true:

It is implicitly defined

All the direct base classes of A have trivial destructors

The classes of all the nonstatic data members of A have trivial destructors

If any of the above are false, then the destructor is nontrivial.

A union member cannot be of a class type that has a nontrivial destructor.

Class members that are class types can have their own destructors. Both base and derived classes

can have destructors, although destructors are not inherited. If a base class A or a member of A has a

destructor, and a class derived from A does not declare a destructor, a default destructor is

Programming and Data Structures II – Unit 1

generated.

The default destructor calls the destructors of the base class and members of the derived class.

The destructors of base classes and members are called in the reverse order of the completion of

their constructor:

1. The destructor for a class object is called before destructors for members and bases are

called.

2. Destructors for nonstatic members are called before destructors for base classes are called.

3. Destructors for nonvirtual base classes are called before destructors for virtual base classes

are called.

When an exception is thrown for a class object with a destructor, the destructor for the temporary

object thrown is not called until control passes out of the catch block.

Destructors are implicitly called when an automatic object (a local object that has been declared

auto or register, or not declared as static or extern) or temporary object passes out of scope. They

are implicitly called at program termination for constructed external and static objects. Destructors

are invoked when you use the delete operator for objects created with the new operator.

For example:

#include <string>

class Y {

private:

char * string;

int number;

public:

// Constructor

Y(const char*, int);

Programming and Data Structures II – Unit 1

// Destructor

~Y() { delete[] string; }

};

// Define class Y constructor

Y::Y(const char* n, int a) {

string = strcpy(new char[strlen(n) + 1 ], n);

number = a;

}

int main () {

// Create and initialize

// object of class Y

Y yobj = Y("somestring", 10);

// ...

// Destructor ~Y is called before

// control returns from main()

}

You can use a destructor explicitly to destroy objects, although this practice is not recommended.

However to destroy an object created with the placement new operator, you can explicitly call the

object's destructor. The following example demonstrates this:

#include <new>

#include <iostream>

using namespace std;

class A {

public:

A() { cout << "A::A()" << endl; }

~A() { cout << "A::~A()" << endl; }

};

int main () {

Programming and Data Structures II – Unit 1

char* p = new char[sizeof(A)];

A* ap = new (p) A;

ap->A::~A();

delete [] p;

}

The statement A* ap = new (p) A dynamically creates a new object of type A not in the free store

but in the memory allocated by p. The statement delete [] p will delete the storage allocated by p,

but the run time will still believe that the object pointed to by ap still exists until you explicitly call

the destructor of A (with the statement ap->A::~A()).

Nonclass types have a pseudo destructor. The following example calls the pseudo destructor for an

integer type:

typedef int I;

int main() {

I x = 10;

x.I::~I();

x = 20;

}

The call to the pseudo destructor, x.I::~I(), has no effect at all. Object x has not been destroyed; the

assignment x = 20 is still valid. Because pseudo destructors require the syntax for explicitly calling

a destructor for a nonclass type to be valid, you can write code without having to know whether or

not a destructor exists for a given type.

What is defference between constructor and destructor

Like constructor the destructor is a member function whose name is the same as the class name but

is preceded by a tilde. For example the destructor of a class integer can be define as :-

~integer(){}

A destructor never takes any argument nor does it return any value. It will invoked implicitly by the

compiler upon exit from the program to clean up storage that is no longer accessible.

Session 4

Programming and Data Structures II – Unit 1

Static members

Class members can be declared using the storage class specifier static in the class member

list. Only one copy of the static member is shared by all objects of a class in a program. When you

declare an object of a class having a static member, the static member is not part of the class object.

Definition

A variable that is part of a class, yet is not part of an object of that class, is called a s t a t i c

member. There is exactly one copy of a static member instead of one copy per object, as for

ordinary non static members. Similarly, a function that needs access to members of a class, yet

doesn’t need to be invoked for a particular object, is called a static member function.

A typical use of static members is for recording data common to all objects of a class. A

static member of a class is a member whose value is the same for every object instantiated. This

means that if one object changes the value of the static member, this change will be reflected in

another object instantiated from the class. The change (or the resulting value) will be the same in all

the instantiated objects. You can also access a static member using the class name without

instantiation. In this part of the series, we look at static members in C++ classes. You can have a

static member along side other members in your class.

Static Property A static property is also called a static data member.

Declaring a Static Property You declare a static property just as you declare any other attribute,

but you precede the declaration expression with the keyword, static and a space. The syntax is:

static Type Ident;

static member is shared by all objects of the class. All static data is initialized to zero when

the first object is created, if no other initialization is present. We can't put it in the class definition

but it can be initialized outside the class as done in the following example by redeclaring the static

variable, using the scope resolution operator :: to identify which class it belongs to.

Example to understand the concept of static data members

Programming and Data Structures II – Unit 1

#include <iostream>

using namespace std;

class Box

{

public:

static int objectCount;

// Constructor definition

Box(double l=2.0, double b=2.0, double h=2.0)

{

cout <<"Constructor called." << endl;

length = l;

breadth = b;

height = h;

// Increase every time object is created

objectCount++;

}

double Volume()

{

return length * breadth * height;

}

private:

double length; // Length of a box

double breadth; // Breadth of a box

double height; // Height of a box

};

// Initialize static member of class Box

int Box::objectCount = 0;

int main(void)

{

Box Box1(3.3, 1.2, 1.5); // Declare box1

Box Box2(8.5, 6.0, 2.0); // Declare box2

// Print total number of objects.

cout << "Total objects: " << Box::objectCount << endl;

return 0;

}

Programming and Data Structures II – Unit 1

When the above code is compiled and executed, it produces the following result:

Constructor called.

Constructor called.

Total objects: 2

Static Function Members:

By declaring a function member as static, you make it independent of any particular object of the

class. A static member function can be called even if no objects of the class exist and the static

functions are accessed using only the class name and the scope resolution operator ::.

A static member function can only access static data member, other static member functions and

any other functions from outside the class.

Static member functions have a class scope and they do not have access to the this pointer of the

class. You could use a static member function to determine whether some objects of the class have

been created or not.

Let us try the following example to understand the concept of static function members:

#include <iostream>

using namespace std;

class Box

{

public:

static int objectCount;

// Constructor definition

Box(double l=2.0, double b=2.0, double h=2.0)

{

cout <<"Constructor called." << endl;

length = l;

breadth = b;

height = h;

// Increase every time object is created

objectCount++;

}

double Volume()

{

Programming and Data Structures II – Unit 1

return length * breadth * height;

}

static int getCount()

{

return objectCount;

}

private:

double length; // Length of a box

double breadth; // Breadth of a box

double height; // Height of a box

};

// Initialize static member of class Box

int Box::objectCount = 0;

int main(void)

{

// Print total number of objects before creating object.

cout << "Inital Stage Count: " << Box::getCount() << endl;

Box Box1(3.3, 1.2, 1.5); // Declare box1

Box Box2(8.5, 6.0, 2.0); // Declare box2

// Print total number of objects after creating object.

cout << "Final Stage Count: " << Box::getCount() << endl;

return 0;

}

When the above code is compiled and executed, it produces the following result:

Inital Stage Count: 0

Constructor called.

Constructor called.

Final Stage Count: 2

Home work:

Write a program To count the object value using the storage keyword static.

Programming and Data Structures II – Unit 1

ALGORITHM:

STEP 1: Start the program.

STEP 2: Declare the class name as Stat with data member s and member functions.

STEP 3: The constructor Stat() which is used to increment the value of count as 1 to to assign the

variable code.

STEP 4: The function showcode() to display the code value.

STEP 5: The function showcount() to display the count value.

STEP 6: Stop the program.

PROGRAM:

#include<iostream.h>

#include<conio.h>

class stat

{

int code;

static int count;

public:

stat()

{

code=++count;

}

void showcode()

{

cout<<"\n\tObject number is :"<<code;

}

static void showcount()

{

cout<<"\n\tCount Objects :"<<count;

}

};

Programming and Data Structures II – Unit 1

int stat::count;

void main()

{

clrscr();

stat obj1,obj2;

obj1.showcount();

obj1.showcode();

obj2.showcount();

obj2.showcode();

getch();

}

Output:

Count Objects: 2

Object Number is: 1

Count Objects: 2

Object Number is: 2

Constant member Functions - const member functions can use const objects.

• Member functions should be declared with the const keyword after them if they can

operate on a const (this) object.

• If the function is not declared const, in can not be applied to a const object, and the

compiler will give an error message.

• A const function can be applied to a non-const object

• A function can only be declared const if it doesn't modify any of its fields.

Syntax

• The const keyword is placed after the function header and before the left brace in both the

prototype and the definition.

Declaration

Programming and Data Structures II – Unit 1

return_type func_name (para_list) const;

Definition

return_type func_name (para_list) const { … }

return_type class_name :: func_name (para_list) const { … }

Makes no modification about the data members (safe function).It is illegal for a const member

function to modify a class data member

Example

In this example from a header file for a vector-like class, the capacity and empty functions

don't change the object, and therefore are declared const. clear may change the object and

therefore can not be declared const.

int capacity() const; // max size before reallocation

void clear(); // delete all items

bool empty() const; // true if contains no elements (size()==0)

const can't be used for constructors and destructors

The purpose of a constructor is to initialize field values, so it must change the object. Similarly for

destructors.

Can overload with non-const functions

There can be both const and non-const functions. The compiler will choose the appropriate one

to call depending on the object they are being applied to. [Note: this seems like more of a

theoretical possibility rather than something that would ever be used. Is there a common use for

defining more than the const version?]

The Date defined so far provides member functions for giving a D a t e a value and

changing it. Unfortunately, we didn’t provide a way of examining the value of a D a t e . This

problem can easily be remedied by adding functions for reading the day, month, and year:

Programming and Data Structures II – Unit 1

c l a s s D a t e {

i n t d , m , y ;

p u b l i c :

i n t d a y () c o n s t { r e t u r n d ; }

i n t m o n t h () c o n s t { r e t u r n m ; }

i n t y e a r () c o n s t ;

/ / ...

};

Note the const after the (empty) argument list in the function declarations. It indicates that these

functions do not modify the state of a Date .

Naturally, the compiler will catch accidental attempts to violate this promise. For example:

i n l i n e i n t D a t e :: y e a r () c o n s t

{

r e t u r n y ++; // error: attempt to change member value in const function

}

When a const member function is defined outside its class, the c o n s t suffix is required:

i n l i n e i n t D a t e :: y e a r () c o n s t // correct

{

r e t u r n y ;

}

i n l i n e i n t D a t e :: y e a r () // error: const missing in member function type

{

r e t u r n y ;

}

In other words, the c o n s t is part of the type of D a t e :: d a y () and D a t e :: y e a r ().

A c o n s t member function can be invoked for both c o n s t and non const objects, whereas a non

const member function can be invoked only for non-const objects.

For example:

Programming and Data Structures II – Unit 1

v o i d f (D a t e & d , c o n s t D a t e & c d )

{

i n t i = d .y e a r (); // ok

d.add_ year(1) ; / / ok

i n t j = c d .y e a r (); // ok

c d .a d d _ y e a r (1 ); // error: cannot change value of const cd

}

Session 5

Member Functions:

A member function of a class is a function that has its definition or its prototype within the

class definition like any other variable. It operates on any object of the class of which it is a

member, and has access to all the members of a class for that object.

Let us take previously defined class to access the members of the class using a member function

instead of directly accessing them:

class Box

{

public:

double length; // Length of a box

double breadth; // Breadth of a box

double height; // Height of a box

double getVolume(void);// Returns box volume

};

Member functions can be defined within the class definition or separately using scope resolution

operator, ::. Defining a member function within the class definition declares the function inline,

even if you do not use the inline specifier. So either you can define Volume() function as below:

class Box

{

public:

double length; // Length of a box

double breadth; // Breadth of a box

double height; // Height of a box

Programming and Data Structures II – Unit 1

double getVolume(void)

{

return length * breadth * height;

}

};

If you like you can define same function outside the class using scope resolution operator, :: as

follows:

double Box::getVolume(void)

{

return length * breadth * height;

}

Here, only important point is that you would have to use class name just before :: operator. A

member function will be called using a dot operator (.) on a object where it will manipulate data

related to that object only as follows:

Box myBox; // Create an object

myBox.getVolume(); // Call member function for the object

Let us put above concepts to set and get the value of different class members in a class:

#include <iostream>

using namespace std;

class Box

{

public:

double length; // Length of a box

double breadth; // Breadth of a box

double height; // Height of a box

// Member functions declaration

double getVolume(void);

void setLength( double len );

void setBreadth( double bre );

void setHeight( double hei );

};

Programming and Data Structures II – Unit 1

// Member functions definitions

double Box::getVolume(void)

{

return length * breadth * height;

}

void Box::setLength( double len )

{

length = len;

}

void Box::setBreadth( double bre )

{

breadth = bre;

}

void Box::setHeight( double hei )

{

height = hei;

}

// Main function for the program

int main( )

{

Box Box1; // Declare Box1 of type Box

Box Box2; // Declare Box2 of type Box

double volume = 0.0; // Store the volume of a box here

// box 1 specification

Box1.setLength(6.0);

Box1.setBreadth(7.0);

Box1.setHeight(5.0);

// box 2 specification

Box2.setLength(12.0);

Box2.setBreadth(13.0);

Box2.setHeight(10.0);

// volume of box 1

volume = Box1.getVolume();

Programming and Data Structures II – Unit 1

cout << "Volume of Box1 : " << volume <<endl;

// volume of box 2

volume = Box2.getVolume();

cout << "Volume of Box2 : " << volume <<endl;

return 0;

}

When the above code is compiled and executed, it produces the following result:

Volume of Box1 : 210

Volume of Box2 : 1560

Example 2:

Consider implementing the concept of a date using a struct to define the representation of a Date

and a set of functions for manipulating variables of this type:

s t r u c t D a t e { // representation

i n t d , m , y ;

};

v o i d i n i t _ d a t e (D a t e & d , i n t , i n t , i n t ); // initialize d

v o i d a d d _ y e a r (D a t e & d , i n t n ); // add n years to d

v o i d a d d _ m o n t h (D a t e & d , i n t n ); // add n months to d

v o i d a d d _ d a y (D a t e & d , i n t n ); // add n days to d

There is no explicit connection between the data type and these functions. Such a connection can

be established by declaring the functions as members:

s t r u c t D a t e {

i n t d , m , y ;

v o i d i n i t (i n t d d , i n t m m , i n t y y ); // initialize

v o i d a d d _ y e a r (i n t n ); // add n years

v o i d a d d _ m o n t h (i n t n ); // add n months

v o i d a d d _ d a y (i n t n ); // add n days

};

Programming and Data Structures II – Unit 1

t o d a y .i n i t (1 6 ,1 0 ,1 9 9 6 );

m y _ b i r t h d a y .i n i t (3 0 ,1 2 ,1 9 5 0 );

D a t e t o m o r r o w = t o d a y ;

t o m o r r o w .a d d _ d a y (1 );

/ / ...

}

Because different structures can have member functions with the same name, we must specify the

structure name when defining a member function:

v o i d D a t e :: i n i t (i n t d d , i n t m m , i n t y y )

{

d = d d ;

m = m m ;

y = y y ;

}

In a member function, member names can be used without explicit reference to an object. In that

case, the name refers to that member of the object for which the function was invoked. For example,

when D a t e :: i n i t () is invoked for t o d a y , m =m m assigns to t o d a y .m . On the other hand,

when D a t e :: i n i t () is invoked for m y _ b i r t h d a y , m =m m assigns to m y _ b i r t h d a y .m

. A class

member function always ‘‘knows’’ for which object it was invoked.

The construct

c l a s s X { ... };

is called a class definition because it defines a new type. For historical reasons, a class definition is

often referred to as a class declaration. Also, like declarations that are not definitions, a class

definition

can be replicated in different source files using #i n c l u d e without violating the onedefinition

rule (

10.2.2 Access Control [class.access]

The declaration of D a t e in the previous subsection provides a set of functions for

manipulating a D a t e . However, it does not specify that those functions should be the only ones to

depend directly on D a t e ’s representation and the only ones to directly access objects of class D a

Programming and Data Structures II – Unit 1

t e . This restriction can be expressed by using a class instead of a struct :

c l a s s D a t e {

i n t d , m , y ;

p u b l i c :

v o i d i n i t (i n t d d , i n t m m , i n t y y ); // initialize

v o i d a d d _ y e a r (i n t n ); // add n years

v o i d a d d _ m o n t h (i n t n ); // add n months

v o i d a d d _ d a y (i n t n ); // add n days

};

The p u b l i c label separates the class body into two parts. The names in the first, private, part can

be used only by member functions. The second, public, part constitutes the public interface to

objects of the class. A struct is simply a c l a s s whose members are public by default; member

functions can be defined and used exactly as before. For example:

i n l i n e v o i d D a t e :: a d d _ y e a r (i n t n )

{

y += n;

}

However, nonmember functions are barred from using private members. For example:

v o i d t i m e w a r p (D a t e & d )

{

d .y =

2 0 0 ; // error: Date::y is private

}

There are several benefits to be obtained from restricting access to a data structure to an

explicitly declared list of functions. For example, any error causing a D a t e to take on an illegal

value (for example, December 36, 1985) must be caused by code in a member function. This

implies that the first stage of debugging – localization – is completed before the program is even

run. This is a special case of the general observation that any change to the behavior of the type D a

Programming and Data Structures II – Unit 1

t e can and must be effected by changes to its members. In particular, if we change the

representation of a class, we need only change the member functions to take advantage of the new

representation. User code directly depends only on the public interface and need not be rewritten

(although it may need to be recompiled). Another advantage is that a potential user need examine

only the definition of the member functions in order to learn to use a class.

The protection of private data relies on restriction of the use of the class member names. It

can therefore be circumvented by address manipulation and explicit type conversion. But this, of

course, is cheating. C++ protects against accident rather than deliberate circumvention (fraud).

Only hardware can protect against malicious use of a generalpurpose language, and even that is

hard to do in realistic systems.

The init() function was added partially because it is generally useful to have a function

that sets the value of an object and partly because making the data private forces us to provide it.

inline function:

C++ inline function is powerful concept that is commonly used with classes. If a function is

inline, the compiler places a copy of the code of that function at each point where the function is

called at compile time.

Any change to an inline function could require all clients of the function to be recompiled because

compiler would need to replace all the code once again otherwise it will continue with old

functionality.

To inline a function, place the keyword inline before the function name and define the function

before any calls are made to the function. The compiler can ignore the inline qualifier in case

defined function is more than a line. This does not change at all the behavior of a function, but is

merely used to suggest the compiler that the code generated by the function body shall be inserted

at each point the function is called, instead of being invoked with a regular function call.

A function definition in a class definition is an inline function definition, even without the use of the

inline specifier.

Following is an example, which makes use of inline function to return max of two numbers:

Programming and Data Structures II – Unit 1

#include <iostream>

using namespace std;

inline int Max(int x, int y)

{

return (x > y)? x : y;

}

// Main function for the program

int main( )

{

cout << "Max (20,10): " << Max(20,10) << endl;

cout << "Max (0,200): " << Max(0,200) << endl;

cout << "Max (100,1010): " << Max(100,1010) << endl;

return 0;

}

When the above code is compiled and executed, it produces the following result:

Max (20,10): 20

Max (0,200): 200

Max (100,1010): 1010

Friend Function

A friend function of a class is defined outside that class' scope but it has the right to access

all private and protected members of the class. Even though the prototypes for friend functions

appear in the class definition, friends are not member functions.

A friend can be a function, function template, or member function, or a class or class template, in which case the entire class and all of its members are friends.

To declare a function as a friend of a class, precede the function prototype in the class definition with keyword friend as follows:

class Box{ double width;public: double length; friend void printWidth( Box box ); void setWidth( double wid );};

To declare all member functions of class ClassTwo as friends of class ClassOne, place a following

Programming and Data Structures II – Unit 1

declaration in the definition of class ClassOne:

friend class ClassTwo;

Consider the following program:

#include <iostream> using namespace std; class Box{ double width;public: friend void printWidth( Box box ); void setWidth( double wid );};

// Member function definitionvoid Box::setWidth( double wid ){ width = wid;}

// Note: printWidth() is not a member function of any class.void printWidth( Box box ){ /* Because printWidth() is a friend of Box, it can directly access any member of this class */ cout << "Width of box : " << box.width <<endl;} // Main function for the programint main( ){ Box box; // set box width without member function box.setWidth(10.0); // Use friend function to print the wdith. printWidth( box ); return 0;}

When the above code is compiled and executed, it produces the following result:

Width of box : 10

Characteristics of Friend Function

• A friend function is not in the scope of the Class in which it has been declared as friend.

• It can not be called using the object of that Class

• It can be invoked like a normal function without any object

• Unlike member functions, it can not use the member names directly.

Programming and Data Structures II – Unit 1

• It can be declared in public or private part without effecting its meaning

• Usually, it has objects as arguments.

Friend Class

A class can also be declared to be the friend of some other class. When we create a friend class then all the member functions of the friend class also become the friend of the other class. This requires the condition that the friend becoming class must be first declared or defined (forwarddeclaration).

#include <iostream>using namespace std;

class MyClass{ // Declare a friend class friend class SecondClass;

public: MyClass() : Secret(0){} void printMember() { cout << Secret << endl; } private: int Secret;};

class SecondClass{ public: void change( MyClass& yourclass, int x ) { yourclass.Secret = x; }};

void main(){ MyClass my_class; SecondClass sec_class; my_class.printMember(); sec_class.change( my_class, 5 ); my_class.printMember();}

Note:we declared friend class SecondClass; in the class MyClass, so we can access Secret in the class SecondClass.

Another property of friendships is that they are not transitive: The friend of a friend is not

Programming and Data Structures II – Unit 1

considered to be a friend unless explicitly specified.

What are Friend Function?

The friend function is a 'non member function'of the class. It can access non public members

of the class. A friend function is external to the class definition.

Advantages of Friend Class

• Provides additional Functionality which is kept outside the class.

• Provides function that need data which is not normally used by the class.

• Allows sharing private class information by a non member function.

Const and volatile functions

Const functions

Declaring a member function with the const keyword specifies that the function is a "read-only"

function that does not modify the object for which it is called.

If you declare a class method const, you are promising that the method won't change the value of

any of the members of the class. To declare a class method constant, put the keyword const after the

parentheses but before the semicolon. The declaration of the constant member function

SomeFunction() takes no arguments and returns void. It looks like this:

void SomeFunction() const;

Accessor functions are often declared as constant functions by using the const modifier. The Cat

class has two accessor functions:

void SetAge(int anAge);

int GetAge();

SetAge() cannot be const because it changes the member variable itsAge. GetAge(), on the other

hand, can and should be const because it doesn't change the class at all. GetAge() simply returns the

Programming and Data Structures II – Unit 1

current value of the member variable itsAge. Therefore, the declaration of these functions should be

written like this:

void SetAge(int anAge);

int GetAge() const;

If you declare a function to be const, and the implementation of that function changes the object by

changing the value of any of its members, the compiler flags it as an error. For example, if you

wrote GetAge() in such a way that it kept count of the number of times that the Cat was asked its

age, it would generate a compiler error. This is because you would be changing the Cat object by

calling this method.

Use const whenever possible. Declare member functions to be const whenever they should not

change the object. This lets the compiler help you find errors; it's faster and less expensive than

doing it yourself.

It is good programming practice to declare as many methods to be const as possible. Each time you

do, you enable the compiler to catch your errors, instead of letting your errors become bugs that will

show up when your program is running.

class c{

static int d;

void f() const {d=0;} //!

}int c::d;

...it has no error

To declare a constant member function, place the const keyword after the closing parenthesis of the

argument list. The const keyword is required in both the declaration and the definition. A constant

member function cannot modify any data members or call any member functions that aren't

constant.

Example

class Date

{

public:

Programming and Data Structures II – Unit 1

Date( int mn, int dy, int yr );

int getMonth() const; // A read-only function

void setMonth( int mn ); // A write function; can't be const

private:

int month;};

int Date::getMonth() const{

return month; // Doesn't modify anything}

void Date::setMonth( int mn ){

month = mn; // Modifies data member}

int main(){

Date MyDate( 7, 4, 1998 );

const Date BirthDate( 1, 18, 1953 );

MyDate.setMonth( 4 ); // Okay

BirthDate.getMonth(); // Okay

BirthDate.setMonth( 4 ); // C2662 Error}

The effects of declaring a variable to be const propagate throughout the program. Once you have a

const object, it cannot be assigned to a non-const reference or use functions that are known to be

capable of changing the state of the object. This is necessary to enforce the const-ness of the object,

but it means you need a way to state that a function should not make changes to an object. In non-

object-oriented code, this is as easy as using const references as demonstrated above.

In C++, however, there's the issue of classes with methods. If you have a const object, you don't

want to call methods that can change the object, so you need a way of letting the compiler know

which methods can be safely called. These methods are called "const functions", and are the only

functions that can be called on a const object. Note, by the way, that only member methods make

sense as const methods. Remember that in C++, every method of an object receives an implicit this

pointer to the object; const methods effectively receive a const this pointer.

The way to declare that a function is safe for const objects is simply to mark it as const; the syntax

for const functions is a little bit peculiar because there's only one place where you can really put the

const: at the end of the function:

<return-value> <class>::<member-function>(<args>) const{ // ...}

Programming and Data Structures II – Unit 1

For instance,

int Loan::calcInterest() const{

return loan_value * interest_rate; }

Note that just because a function is declared const that doesn't prohibit non-const functions from

using it; the rule is this:

Const functions can always be called

Non-const functions can only be called by non-const objects

That makes sense: if you have a const function, all that means is that it guarantees it won't change

the object. So just because it is const doesn't mean that non-const objects can't use it.

As a matter of fact, const functions have a slightly stronger restriction than merely that they cannot

modify the data. They must make it so that they cannot be used in a way that would allow you to

use them to modify const data. This means that when const functions return references or pointers

to members of the class, they must also be const.

Volatile functions

C++ also supports volatile member functions. You declare a member function with the volatile

specifier to ensure that it can be called safely for a volatile object:

class B

{

int x;

public:

void f() volatile; // volatile member function

};

int main()

{

volatile B b; // b is a volatile object

b.f(); // call a volatile member function safely

}

Programming and Data Structures II – Unit 1

The object b is declared volatile. Calling a non-volatile member function from this object is unsafe,

because b's state might have been changed by a different thread in the meantime. To ensure that f()

can be called safely for a volatile object, it's declared volatile too.

Session 6

Pointers:

Pointers refer the memory location of a variable using a reference operator. The reference

operator is the "&" symbol, which means the "address of".

Pointers can be used to directly access the value stored in the variable using the "*" operator known

as a "dereference operator".Another dereference operator is "->", which dereferences to a structure

or union.

For a type T , T * is the type ‘‘pointer to T .’’ That is, a variable of type T * can hold the

address of

an object of type T . For example:

c h a r c = ´a ´;

c h a r * p = &c ; // p holds the address of c

or graphically:

Unfortunately, pointers to arrays and pointers to functions need a more complicated notation:

i n t * p i ; // pointer to int

c h a r ** p p c ; // pointer to pointer to char

i n t * a p [1 5 ]; // array of 15 pointers to ints

i n t (*f p )(c h a r *); // pointer to function taking a char* argument; returns an int

i n t * f (c h a r *); // function taking a char* argument; returns a pointer to int

The fundamental operation on a pointer is dereferencing, that is, referring to the object pointed

to by the pointer. This operation is also called indirection. The dereferencing operator is (prefix)

Programming and Data Structures II – Unit 1

unary *. For example:

c h a r c = ´a ´;

c h a r * p = &c ; // p holds the address of c

c h a r c 2 = *p ; // c2 == ’a’

The variable pointed to by p is c , and the value stored in c is ´a ´, so the value of *p assigned to c 2

is ´a ´.

It is possible to perform some arithmetic operations on pointers to array elements. Pointers

to functions can be extremely useful;

The implementation of pointers is intended to map directly to the addressing mechanisms of the

machine on which the program runs. Most machines can address a byte. Those that can’t tend to

have hardware to extract bytes from words. On the other hand, few machines can directly address

an individual bit. Consequently, the smallest object that can be independently allocated and

pointed to using a builtin pointer type is a c h a r . Note that a b o o l occupies at least as much

space as a c h a r . To store smaller values more compactly, you can use logical operations or bit

fields in structures

5.1.1 Zero [ptr.zero]

Zero (0 ) is an i n t . Because of standard conversions (§C.6.2.3), 0 can be used as a constant of any

integral (§4.1.1), floatingpoint,

pointer, or pointertomember

type. The type of zero will be determined

by context. Zero will typically (but not necessarily) be represented by the bit pattern allzeros

of the appropriate size.

No object is allocated with the address 0 . Consequently, 0 acts as a pointer literal, indicating

that a pointer doesn’t refer to an object.

In C, it has been popular to define a macro N U L L to represent the zero pointer. Because of

C++’s tighter type checking, the use of plain 0 , rather than any suggested N U L L macro, leads to

fewer problems. If you feel you must define N U L L , use c o n s t i n t N U L L = 0 ;

The c o n s t qualifier prevents accidental redefinition of N U L L and ensures that N U L L can be

Programming and Data Structures II – Unit 1

used where a constant is required.

#include <iostream.h>

int main ()

{

int value;

int * ptr;

ptr = &value;

*ptr = 12;

cout << "The value is:: " << value << endl;

return 0;

}

Result:

The value is:: 12

In the above example an integer "value" and a pointer "ptr" is declared first. The address of

the variable "value" is pointed by the "ptr". Now the values of the "ptr" is assigned to 12.

References:

A reference is an alternative name for an object. The main use of references is for specifying

arguments and return values for functions in general and for overloaded operators in particular.

The notation X & means reference to X . For example:

v o i d f ()

{

i n t i = 1 ;

i n t & r = i ; // r and i now refer to the same int

i n t x = r ; // x = 1

r = 2 ; // i = 2

}

To ensure that a reference is a name for something (that is, bound to an object), we must initialize

the reference. For example:

Programming and Data Structures II – Unit 1

i n t i = 1 ;

i n t & r 1 = i ; // ok: r1 initialized

i n t & r 2 ; // error: initializer missing

e x t e r n i n t & r 3 ; // ok: r3 initialized elsewhere

Initialization of a reference is something quite different from assignment to it. Despite appearances,

no operator operates on a reference. For example:

v o i d g ()

{

i n t i i = 0 ;

i n t & r r = i i ;

r r ++; // ii is incremented to 1

i n t * p p = &r r ; // pp points to ii

}

This is legal, but r r ++ does not increment the reference r r ; rather, ++ is applied to an i n t that

happens to be i i . Consequently, the value of a reference cannot be changed after initialization; it

always refers to the object it was initialized to denote. To get a pointer to the object denoted by a

reference r r , we can write &r r .

The obvious implementation of a reference is as a (constant) pointer that is dereferenced each

time it is used. It doesn’t do much harm thinking about references that way, as long as one

remembers that a reference isn’t an object that can be manipulated the way a pointer is:

i i : 1

p p : &i i

r r :

In some cases, the compiler can optimize away a reference so that there is no object representing

that reference at runtime.

Initialization of a reference is trivial when the initializer is an lvalue ; . The initializer for a ‘‘plain’’

T & must be an lvalue of type T .

The initializer for a c o n s t T & need not be an lvalue or even of type T . In such cases,

[1] first, implicit type conversion to T is applied if necessary

Programming and Data Structures II – Unit 1

[2] then, the resulting value is placed in a temporary variable of type T ; and

[3] finally, this temporary variable is used as the value of the initializer.

Consider:

d o u b l e & d r = 1 ; // error: lvalue needed

c o n s t d o u b l e & c d r = 1 ; // ok

The interpretation of this last initialization might be:

d o u b l e t e m p = d o u b l e (1 ); // first create a temporary with the right value

c o n s t d o u b l e & c d r = t e m p ; // then use the temporary as the initializer for cdr

A temporary created to hold a reference initializer persists until the end of its reference’s

scope. References to variables and references to constants are distinguished because the

introduction of a temporary in the case of the variable is highly errorprone; an assignment to the

variable would become an assignment to the – soon to disappear – temporary. No such problem

exists for references to constants, and references to constants are often important as function

arguments. A reference can be used to specify a function argument so that the function can change

the value of an object passed to it.

For example:

v o i d i n c r e m e n t (i n t & a a ) { a a ++; }

v o i d f ()

{

i n t x = 1 ;

i n c r e m e n t (x ); // x = 2

}

The semantics of argument passing are defined to be those of initialization, so when called,

i n c r e m e n t ’s argument a a became another name for x . To keep a program readable, it is often

best to avoid functions that modify their arguments. Instead, you can return a value from the

function explicitly or require a pointer argument:

Programming and Data Structures II – Unit 1

i n t n e x t (i n t p ) { r e t u r n p +1 ; }

v o i d i n c r (i n t * p ) { (*p )++; }

v o i d g ()

{

i n t x = 1 ;

i n c r e m e n t (x ); // x = 2

x = n e x t (x ); // x = 3

i n c r (&x ); // x = 4

}

The i n c r e m e n t (x ) notation doesn’t give a clue to the reader that x ’s value is being

modified, the way x =n e x t (x ) and i n c r (&x ) does. Consequently ‘‘plain’’ reference arguments

should be used only where the name of the function gives a strong hint that the reference argument

is modified.

References can also be used to define functions that can be used on both the lefthand and

righthand sides of an assignment. Again, many of the most interesting uses of this are found in the

design of nontrivial userdefined types. As an example, let us define a simple associative array.

First, we define struct Pair like this:

s t r u c t P a i r

{

s t r i n g n a m e ;

d o u b l e v a l ;

};

The basic idea is that a s t r i n g has a floatingpoint value associated with it. It is easy to define a

function, v a l u e (), that maintains a data structure consisting of one P a i r for each different string

that has been presented to it. To shorten the presentation, a very simple (and inefficient)

implementation is used:

v e c t o r <P a i r > p a i r s ;

d o u b l e & v a l u e (c o n s t s t r i n g & s )

/*

maintain a set of Pairs:

search for s, return its value if found; otherwise make a new Pair and return the default value 0

*/

Programming and Data Structures II – Unit 1

{

f o r (i n t i = 0 ; i < p a i r s .s i z e (); i ++)

i f (s == p a i r s [i ].n a m e ) r e t u r n p a i r s [i ].v a l ;

P a i r p = { s , 0 };

p a i r s .p u s h _ b a c k (p ); // add Pair at end

r e t u r n p a i r s [p a i r s .s i z e ()1

].v a l ;

}

This function can be understood as an array of floatingpoint values indexed by character strings.

For a given argument string, v a l u e () finds the corresponding floatingpoint object (not the value

of the corresponding floatingpoint object); it then returns a reference to it. For example:

i n t m a i n () // count the number of occurrences of each word on input

{

s t r i n g b u f ;

w h i l e (c i n >>b u f ) v a l u e (b u f )++;

f o r (v e c t o r <P a i r >:: c o n s t _ i t e r a t o r p = p a i r s .b e g i n (); p !=p a i r s .e n d (); +

+p )

c o u t << p >

n a m e << ": " << p >

v a l << ´\ n ´;

}

Each time around, the w h i l e loop reads one word from the standard input stream c i n into the

string b u f and then updates the counter associated with it. Finally, the resulting table of different

words in the input, each with its number of occurrences, is printed. For example, given the input

a a b b b b a a a a b b a a a a

this program will produce:

a a : 5

b b : 3

It is easy to refine this into a proper associative array type by using a template class with the

selection operator [] overloaded . It is even easier just to use the standard library m a p.

Example

int main()

Programming and Data Structures II – Unit 1

{

int y=10;

int &r= y;

cout<<r;

}

Result: 10.

Session 7

Role of 'this' Pointer:

A unique keyword called this to represent an object has invokes a member function. The this

pointer is an implicit parameter to all member functions. Therefore, inside a member function, this

may be used to refer to the invoking object.

Friend functions do not have a this pointer, because friends are not members of a class. Only

member functions have a this pointer.

Let us try the following example to understand the concept of this pointer:

#include <iostream>

using namespace std;

class Box

{

public:

// Constructor definition

Box(double l=2.0, double b=2.0, double h=2.0)

{

cout <<"Constructor called." << endl;

length = l;

breadth = b;

height = h;

}

double Volume()

Programming and Data Structures II – Unit 1

{

return length * breadth * height;

}

int compare(Box box)

{

return this->Volume() > box.Volume();

}

private:

double length; // Length of a box

double breadth; // Breadth of a box

double height; // Height of a box

};

int main(void)

{

Box Box1(3.3, 1.2, 1.5); // Declare box1

Box Box2(8.5, 6.0, 2.0); // Declare box2

if(Box1.compare(Box2))

{

cout << "Box2 is smaller than Box1" <<endl;

}

else

{

cout << "Box2 is equal to or larger than Box1" <<endl;

}

return 0;

}

When the above code is compiled and executed, it produces the following result:

Constructor called.

Constructor called.

Box2 is equal to or larger than Box1

Programming and Data Structures II – Unit 1

Session 8

Storage Classes

A storage class defines the scope (visibility) and life-time of variables and/or functions

within a C++ Program. These specifiers precede the type that they modify. There are following

storage classes, which can be used in a C++ Program

• auto

• register

• static

• extern

• mutable

The auto Storage Class

The auto storage class is the default storage class for all local variables.

{

int mount;

auto int month;

}

The example above defines two variables with the same storage class, auto can only be used within

functions, i.e., local variables.

The register Storage Class

The register storage class is used to define local variables that should be stored in a register

instead of RAM. This means that the variable has a maximum size equal to the register size (usually

one word) and can't have the unary '&' operator applied to it (as it does not have a memory

location).

{

register int miles;

}

Programming and Data Structures II – Unit 1

The register should only be used for variables that require quick access such as counters. It should

also be noted that defining 'register' does not mean that the variable will be stored in a register. It

means that it MIGHT be stored in a register depending on hardware and implementation

restrictions.

The static Storage Class

The static storage class instructs the compiler to keep a local variable in existence during the

life-time of the program instead of creating and destroying it each time it comes into and goes out of

scope. Therefore, making local variables static allows them to maintain their values between

function calls.

The static modifier may also be applied to global variables. When this is done, it causes that

variable's scope to be restricted to the file in which it is declared.

In C++, when static is used on a class data member, it causes only one copy of that member to be

shared by all objects of its class.

#include <iostream>

// Function declaration

void func(void);

static int count = 10; /* Global variable */

main()

{

while(count--)

{

func();

}

return 0;

}

// Function definition

void func( void )

{

static int i = 5; // local static variable

Programming and Data Structures II – Unit 1

i++;

std::cout << "i is " << i ;

std::cout << " and count is " << count << std::endl;

}

When the above code is compiled and executed, it produces the following result:

i is 6 and count is 9

i is 7 and count is 8

i is 8 and count is 7

i is 9 and count is 6

i is 10 and count is 5

i is 11 and count is 4

i is 12 and count is 3

i is 13 and count is 2

i is 14 and count is 1

i is 15 and count is 0

The extern Storage Class

The extern storage class is used to give a reference of a global variable that is visible to ALL the

program files. When you use 'extern' the variable cannot be initialized as all it does is point the

variable name at a storage location that has been previously defined.

When you have multiple files and you define a global variable or function, which will be used in

other files also, then extern will be used in another file to give reference of defined variable or

function. Just for understanding extern is used to declare a global variable or function in another

file.

The extern modifier is most commonly used when there are two or more files sharing the same

global variables or functions as explained below.

First File: main.cpp

#include <iostream>

int count ;

extern void write_extern();

Programming and Data Structures II – Unit 1

main()

{

count = 5;

write_extern();

}

Second File: support.cpp

#include <iostream>

extern int count;

void write_extern(void)

{

std::cout << "Count is " << count << std::endl;

}

Here, extern keyword is being used to declare count in another file. Now compile these two files as

follows:

$g++ main.cpp support.cpp -o write

This will produce write executable program, try to execute write and check the result as follows:

$./write

5

The mutable Storage Class

The mutable specifier applies only to class objects, which are discussed later in this tutorial. It

allows a member of an object to override constness. That is, a mutable member can be modified by

a const member function.

Session 9

Functions:

Programming and Data Structures II – Unit 1

Functions allow to structure programs in segments of code to perform individual tasks.

In C++, a function is a group of statements that is given a name, and which can be called from some

point of the program. The most common syntax to define a function is:

type name ( parameter1, parameter2, ...) { statements }

Where:

- type is the type of the value returned by the function.

- name is the identifier by which the function can be called.

- parameters (as many as needed): Each parameter consists of a type followed by an identifier,

with each parameter being separated from the next by a comma. Each parameter looks very much

like a regular variable declaration (for example: int x), and in fact acts within the function as a

regular variable which is local to the function. The purpose of parameters is to allow passing

arguments to the function from the location where it is called from.

- statements is the function's body. It is a block of statements surrounded by braces { } that

specify what the function actually does.

Let's have a look at an example:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

// function example

#include <iostream>

using namespace std;

int addition (int a, int b)

{

int r;

r=a+b;

return r;

}

int main ()

{

int z;

z = addition (5,3);

cout << "The result is " << z;

OUTPUT:

The result is 8

Programming and Data Structures II – Unit 1

17 }

This program is divided in two functions: addition and main. Remember that no matter

the order in which they are defined, a C++ program always starts by calling main. In fact, main is

the only function called automatically, and the code in any other function is only executed if its

function is called from main (directly or indirectly).

In the example above, main begins by declaring the variable z of type int, and right after

that, it performs the first function call: it calls addition. The call to a function follows a structure

very similar to its declaration. In the example above, the call to addition can be compared to its

definition just a few lines earlier:

he parameters in the function declaration have a clear correspondence to the arguments

passed in the function call. The call passes two values, 5 and 3, to the function; these correspond to

the parameters a and b, declared for function addition.

At the point at which the function is called from within main, the control is passed to

function addition: here, execution of main is stopped, and will only resume once the

addition function ends. At the moment of the function call, the value of both arguments (5 and

3) are copied to the local variables int a and int b within the function.

Then, inside addition, another local variable is declared (int r), and by means of the

expression r=a+b, the result of a plus b is assigned to r; which, for this case, where a is 5 and b is

3, means that 8 is assigned to r.

The final statement within the function:

return r;

Ends function addition, and returns the control back to the point where the function was

called; in this case: to function main. At this precise moment, the program resumes its course on

Programming and Data Structures II – Unit 1

main returning exactly at the same point at which it was interrupted by the call to addition. But

additionally, because addition has a return type, the call is evaluated as having a value, and this

value is the value specified in the return statement that ended addition: in this particular case,

the value of the local variable r, which at the moment of the return statement had a value of 8.

Therefore, the call to addition is an expression with the value returned by the function,

and in this case, that value, 8, is assigned to z. It is as if the entire function call

(addition(5,3)) was replaced by the value it returns (i.e., 8).

Then main simply prints this value by calling:

cout << "The result is " << z;

A function can actually be called multiple times within a program, and its argument is

naturally not limited just to literals:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// function example

#include <iostream>

using namespace std;

int subtraction (int a, int b)

{

int r;

r=a-b;

return r;

}

int main ()

{

int x=5, y=3, z;

z = subtraction (7,2);

cout << "The first result is " << z << '\n';

cout << "The second result is " << subtraction (7,2) << '\n';

cout << "The third result is " << subtraction (x,y) << '\n';

z= 4 + subtraction (x,y);

cout << "The fourth result is " << z << '\n';

}

OUTPUT

The first result is 5

The second result is 5

The third result is 2

The fourth result is 6

Programming and Data Structures II – Unit 1

Similar to the addition function in the previous example, this example defines a

subtract function, that simply returns the difference between its two parameters. This time,

main calls this function several times, demonstrating more possible ways in which a function can

be called.

Let's examine each of these calls, bearing in mind that each function call is itself an

expression that is evaluated as the value it returns. Again, you can think of it as if the function call

was itself replaced by the returned value:

z = subtraction (7,2);

cout << "The first result is " << z;

If we replace the function call by the value it returns (i.e., 5), we would

have:

z = 5;

cout << "The first result is " << z;

With the same procedure, we could interpret:

cout << "The second result is " << subtraction (7,2);

as:

cout << "The second result is " << 5;

since 5 is the value returned by subtraction (7,2).

In the case of:

cout << "The third result is " << subtraction (x,y);

The arguments passed to subtraction are variables instead of literals.

That is also valid, and works fine. The function is called with the values x and

y have at the moment of the call: 5 and 3 respectively, returning 2 as result.

The fourth call is again similar:

z = 4 + subtraction (x,y);

The only addition being that now the function call is also an operand of

an addition operation. Again, the result is the same as if the function call was

Programming and Data Structures II – Unit 1

replaced by its result: 6. Note, that thanks to the commutative property of

additions, the above can also be written as:

z = subtraction (x,y) + 4;

With exactly the same result. Note also that the semicolon does not necessarily go after the

function call, but, as always, at the end of the whole statement. Again, the logic behind may be

easily seen again by replacing the function calls by their returned value:

z = 4 + 2; // same as z = 4 + substraction (x,y);

z = 2 + 4; // same as z = substraction (x,y) + 4;

Functions with no type. The use of void

The syntax shown above for functions:

type name ( argument1, argument2 ...) { statements }

Requires the declaration to begin with a type. This is the type of the value returned by the

function. But what if the function does not need to return a value? In this case, the type to be used is

void, which is a special type to represent the absence of value. For example, a function that simply

prints a message may not need to return any value:

1

2

3

4

5

6

7

8

9

10

11

12

13

// void function example

#include <iostream>

using namespace std;

void printmessage ()

{

cout << "I'm a function!";

}

int main ()

{

printmessage ();

}

OUTPUT:

I'm a function!

Programming and Data Structures II – Unit 1

void can also be used in the function's parameter list to explicitly specify that the function takes no

actual parameters when called. For example, printmessage could have been declared as:

1

2

3

4

void printmessage (void)

{

cout << "I'm a function!";

}

In C++, an empty parameter list can be used instead of void with same meaning, but the use of

void in the argument list was popularized by the C language, where this is a requirement.

Something that in no case is optional are the parentheses that follow the function name,

neither in its declaration nor when calling it. And even when the function takes no parameters, at

least an empty pair of parentheses shall always be appended to the function name. See how

printmessage was called in an earlier example:

printmessage ();

The parentheses are what differentiate functions from other kinds of declarations or

statements. The following would not call the function:

printmessage;

The return value of main

You may have noticed that the return type of main is int, but most examples in this and

earlier chapters did not actually return any value from main.

Well, there is a catch: If the execution of main ends normally without encountering a return

statement the compiler assumes the function ends with an implicit return statement:

return 0;

Note that this only applies to function main for historical reasons. All other functions with a

return type shall end with a proper return statement that includes a return value, even if this is

Programming and Data Structures II – Unit 1

never used. When main returns zero (either implicitly or explicitly), it is interpreted by the

environment as that the program ended successfully. Other values may be returned by main, and

some environments give access to that value to the caller in some way, although this behavior is not

required nor necessarily portable between platforms. The values for main that are guaranteed to be

interpreted in the same way on all platforms are:

value description0 The program was successful

EXIT_SUCCESSThe program was successful (same as above).

This value is defined in header <cstdlib>.

EXIT_FAILUREThe program failed.

This value is defined in header <cstdlib>.

Because the implicit return 0; statement for main is a tricky exception, some authors

consider it good practice to explicitly write the statement.

Arguments passed by value and by reference

In the functions seen earlier, arguments have always been passed by value. This means that,

when calling a function, what is passed to the function are the values of these arguments on the

moment of the call, which are copied into the variables represented by the function parameters. For

example, take:

1

2

int x=5, y=3, z;

z = addition ( x, y );

In this case, function addition is passed 5 and 3, which are copies of the values of x and y,

respectively. These values (5 and 3) are used to initialize the variables set as parameters in the

function's definition, but any modification of these variables within the function has no effect on the

values of the variables x and y outside it, because x and y were themselves not passed to the

function on the call, but only copies of their values at that moment.

In certain cases, though, it may be useful to access an external variable from within a

function. To do that, arguments can be passed by reference, instead of by value. For example, the

Programming and Data Structures II – Unit 1

function duplicate in this code duplicates the value of its three arguments, causing the variables

used as arguments to actually be modified by the call:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

// passing parameters by reference

#include <iostream>

using namespace std;

void duplicate (int& a, int& b, int& c)

{

a*=2;

b*=2;

c*=2;

}

int main ()

{

int x=1, y=3, z=7;

duplicate (x, y, z);

cout << "x=" << x << ", y=" << y << ", z=" << z;

return 0;

}

x=2, y=6, z=14Edit & Run

To gain access to its arguments, the function declares its parameters as references. In C++,

references are indicated with an ampersand (&) following the parameter type, as in the parameters

taken by duplicate in the example above.

When a variable is passed by reference, what is passed is no longer a copy, but the variable

itself, the variable identified by the function parameter, becomes somehow associated with the

argument passed to the function, and any modification on their corresponding local variables within

the function are reflected in the variables passed as arguments in the call.

In fact, a, b, and c become aliases of the arguments passed on the function call (x, y, and z)

and any change on a within the function is actually modifying variable x outside the function. Any

change on b modifies y, and any change on c modifies z. That is why when, in the example,

function duplicate modifies the values of variables a, b, and c, the values of x, y, and z are

affected.

Programming and Data Structures II – Unit 1

If instead of defining duplicate as:

void duplicate (int& a, int& b, int& c)

Was it to be defined without the ampersand signs as:

void duplicate (int a, int b, int c)

The variables would not be passed by reference, but by value, creating instead copies of their

values. In this case, the output of the program would have been the values of x, y, and z without

being modified (i.e., 1, 3, and 7).

Efficiency considerations and const references

Calling a function with parameters taken by value causes copies of the values to be made.

This is a relatively inexpensive operation for fundamental types such as int, but if the parameter is

of a large compound type, it may result on certain overhead. For example, consider the following

function:

1

2

3

4

string concatenate (string a, string b)

{

return a+b;

}

This function takes two strings as parameters (by value), and returns the result of

concatenating them. By passing the arguments by value, the function forces a and b to be copies of

the arguments passed to the function when it is called. And if these are long strings, it may mean

copying large quantities of data just for the function call.

But this copy can be avoided altogether if both parameters are made references:

1

2

3

string concatenate (string& a, string& b)

{

return a+b;

Programming and Data Structures II – Unit 1

4 }

Arguments by reference do not require a copy. The function operates directly on (aliases of)

the strings passed as arguments, and, at most, it might mean the transfer of certain pointers to the

function. In this regard, the version of concatenate taking references is more efficient than the

version taking values, since it does not need to copy expensive-to-copy strings.

On the flip side, functions with reference parameters are generally perceived as functions

that modify the arguments passed, because that is why reference parameters are actually for.

The solution is for the function to guarantee that its reference parameters are not going to be

modified by this function. This can be done by qualifying the parameters as constant:

1

2

3

4

string concatenate (const string& a, const string& b)

{

return a+b;

}

By qualifying them as const, the function is forbidden to modify the values of neither a

nor b, but can actually access their values as references (aliases of the arguments), without having

to make actual copies of the strings.

Therefore, const references provide functionality similar to passing arguments by value,

but with an increased efficiency for parameters of large types. That is why they are extremely

popular in C++ for arguments of compound types. Note though, that for most fundamental types,

there is no noticeable difference in efficiency, and in some cases, const references may even be less

efficient!

Inline functions

Calling a function generally causes a certain overhead (stacking arguments, jumps, etc...),

and thus for very short functions, it may be more efficient to simply insert the code of the function

where it is called, instead of performing the process of formally calling a function.

Programming and Data Structures II – Unit 1

Preceding a function declaration with the inline specifier informs the compiler that inline

expansion is preferred over the usual function call mechanism for a specific function. This does not

change at all the behavior of a function, but is merely used to suggest the compiler that the code

generated by the function body shall be inserted at each point the function is called, instead of being

invoked with a regular function call.

For example, the concatenate function above may be declared inline as:

1

2

3

4

inline string concatenate (const string& a, const string& b)

{

return a+b;

}

This informs the compiler that when concatenate is called, the program prefers the

function to be expanded inline, instead of performing a regular call. inline is only specified in

the function declaration, not when it is called.

Note that most compilers already optimize code to generate inline functions when they see

an opportunity to improve efficiency, even if not explicitly marked with the inline specifier.

Therefore, this specifier merely indicates the compiler that inline is preferred for this function,

although the compiler is free to not inline it, and optimize otherwise. In C++, optimization is a task

delegated to the compiler, which is free to generate any code for as long as the resulting behavior is

the one specified by the code.

Default values in parameters

In C++, functions can also have optional parameters, for which no arguments are required in

the call, in such a way that, for example, a function with three parameters may be called with only

two. For this, the function shall include a default value for its last parameter, which is used by the

function when called with fewer arguments. For example:

1

2

3

4

// default values in functions

#include <iostream>

using namespace std;

6

5

Programming and Data Structures II – Unit 1

5

6

7

8

9

10

11

12

13

14

15

16

17

int divide (int a, int b=2)

{

int r;

r=a/b;

return (r);

}

int main ()

{

cout << divide (12) << '\n';

cout << divide (20,4) << '\n';

return 0;

}

In this example, there are two calls to function divide. In the first one:

divide (12)

The call only passes one argument to the function, even though the function has two

parameters. In this case, the function assumes the second parameter to be 2 (notice the function

definition, which declares its second parameter as int b=2). Therefore, the result is 6.

In the second call:

divide (20,4)

The call passes two arguments to the function. Therefore, the default value for b (int

b=2) is ignored, and b takes the value passed as argument, that is 4, yielding a result of 5.

Declaring functions

In C++, identifiers can only be used in expressions once they have been declared. For

example, some variable x cannot be used before being declared with a statement, such as:

int x;

The same applies to functions. Functions cannot be called before they are declared. That is

why, in all the previous examples of functions, the functions were always defined before the main

function, which is the function from where the other functions were called. If main were defined

Programming and Data Structures II – Unit 1

before the other functions, this would break the rule that functions shall be declared before being

used, and thus would not compile.

The prototype of a function can be declared without actually defining the function

completely, giving just enough details to allow the types involved in a function call to be known.

Naturally, the function shall be defined somewhere else, like later in the code. But at least, once

declared like this, it can already be called.

The declaration shall include all types involved (the return type and the type of its

arguments), using the same syntax as used in the definition of the function, but replacing the body

of the function (the block of statements) with an ending semicolon.

The parameter list does not need to include the parameter names, but only their types.

Parameter names can nevertheless be specified, but they are optional, and do not need to necessarily

match those in the function definition. For example, a function called protofunction with two

int parameters can be declared with either of these statements:

1

2

int protofunction (int first, int second);

int protofunction (int, int);

Anyway, including a name for each parameter always improves legibility of the declaration.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// declaring functions prototypes

#include <iostream>

using namespace std;

void odd (int x);

void even (int x);

int main()

{

int i;

do {

cout << "Please, enter number (0 to exit): ";

cin >> i;

odd (i);

Please, enter number (0 to exit): 9

It is odd.

Please, enter number (0 to exit): 6

It is even.

Please, enter number (0 to exit): 1030

It is even.

Please, enter number (0 to exit): 0

It is even.

Programming and Data Structures II – Unit 1

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

} while (i!=0);

return 0;

}

void odd (int x)

{

if ((x%2)!=0) cout << "It is odd.\n";

else even (x);

}

void even (int x)

{

if ((x%2)==0) cout << "It is even.\n";

else odd (x);

}

This example is indeed not an example of efficiency. You can probably write yourself a

version of this program with half the lines of code. Anyway, this example illustrates how functions

can be declared before its definition:

The following lines:

1

2

void odd (int a);

void even (int a);

Declare the prototype of the functions. They already contain all what is necessary to call

them, their name, the types of their argument, and their return type (void in this case). With these

prototype declarations in place, they can be called before they are entirely defined, allowing for

example, to place the function from where they are called (main) before the actual definition of

these functions.

But declaring functions before being defined is not only useful to reorganize the order of

functions within the code. In some cases, such as in this particular case, at least one of the

declarations is required, because odd and even are mutually called; there is a call to even in odd

and a call to odd in even. And, therefore, there is no way to structure the code so that odd is

Programming and Data Structures II – Unit 1

defined before even, and even before odd.

Recursivity

Recursivity is the property that functions have to be called by themselves. It is useful for

some tasks, such as sorting elements, or calculating the factorial of numbers. For example, in order

to obtain the factorial of a number (n!) the mathematical formula would be:

n! = n * (n-1) * (n-2) * (n-3) ... * 1

More concretely, 5! (factorial of 5) would be:

5! = 5 * 4 * 3 * 2 * 1 = 120

And a recursive function to calculate this in C++ could be:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

// factorial calculator

#include <iostream>

using namespace std;

long factorial (long a)

{

if (a > 1)

return (a * factorial (a-1));

else

return 1;

}

int main ()

{

long number = 9;

cout << number << "! = " << factorial (number);

return 0;

}

9! = 362880

Notice how in function factorial we included a call to itself, but only if the argument passed

was greater than 1, since, otherwise, the function would perform an infinite recursive loop, in which

once it arrived to 0, it would continue multiplying by all the negative numbers (probably provoking

a stack overflow at some point during runtime)