Professional Documents
Culture Documents
CHAPTER - 1
1.1. C++ CLASS OVERVIEW- BASIC OOP CONCEPTS:
In this tutorial you will learn about Objects, Classes, Inheritance, Data Abstraction, Data
Encapsulation, Polymorphism, Overloading, and Reusability.
Before starting to learn C++ it is essential to have a basic knowledge of the concepts of
Object oriented programming. Some of the important object oriented features are namely:
Objects
Classes
Inheritance
Data Abstraction
Data Encapsulation
Polymorphism
Overloading
Reusability
In order to understand the basic concepts in C++, a programmer must have a good knowledge
of the basic terminology in object-oriented programming. Below is a brief outline of the
concepts of object-oriented programming languages :
Objects:
Object is the basic unit of object-oriented programming. Objects are identified by its unique
name. An object represents a particular instance of a class. There can be more than one
instance of a class. Each instance of a class can hold its own relevant data.
An Object is a collection of data members and associated member functions also known as
methods.
Classes:
Classes are data types based on which objects are created. Objects with similar properties and
methods are grouped together to form a Class. Thus a Class represents a set of individual
objects. Characteristics of an object are represented in a class as Properties. The actions that
can be performed by objects become functions of the class and are referred to as Methods.
For example consider we have a Class of Cars under which Santro Xing, Alto and WaganR
represents individual Objects. In this context each Car Object will have its own, Model, Year
of Manufacture , Color, Top Speed, Engine Power etc., which form Properties of the Car
class and the associated actions i.e., object functions like Start, Move, and Stop form the
Methods of Car Class.
No memory is allocated when a class is created. Memory is allocated only when an object is
created, i.e., when an instance of a class is created.
Inheritance:
Inheritance is the process of forming a new class from an existing class or base class. The
base class is also known as parent class or super class. The new class that is formed is
called derived class. Derived class is also known as a child class or sub class. Inheritance
helps in reducing the overall code size of the program, which is an important concept in
object-oriented programming.
Data Abstraction:
Data Abstraction increases the power of programming language by creating user defined data
types. Data Abstraction also represents the needed information in the program without
presenting the details.
Data Encapsulation:
Data Encapsulation combines data and functions into a single unit called Class. When using
Data Encapsulation, data is not accessed directly; it is only accessible through the functions
present inside the class. Data Encapsulation enables the important concept of data hiding
possible.
Polymorphism:
Polymorphism allows routines to use variables of different types at different times. An
operator or function can be given different meanings or functions. Polymorphism refers to a
single function or multi-functioning operator performing in different ways.
Overloading:
Overloading is one type of Polymorphism. It allows an object to have different meanings,
depending on its context. When an existing operator or function begins to operate on new
data type, or class, it is understood to be overloaded.
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.
1.3.OBJECTS:
A class is the collection of related data and function under a single name. A C++
program can have any number of classes. When related data and functions are kept
under a class, it helps to visualize the complex problem efficiently and effectively.
The above code specifies var is a variable of type integer; int is used for specifying
variable var is of integer type. Similarly, class are also just the specification for
objects and object bears the property of that class.
Example of Class:
class temp
{
private:
int data1;
float data2;
public:
void func1()
{ data1=2; }
float func2(){
data2=3.5;
retrun data;
}
};
Explanation:
As mentioned, definition of class starts with keyword class followed by name of
class(temp) in this case. The body of that class is inside the curly brackets and
terminated by semicolon at the end. There are two keywords: private and public
mentioned inside the body of class.
C++ Objects:
When class is defined, only specification for the object is defined. Object has same
relationship to class as variable has with the data type. Objects can be defined in
similary way as structure is defined.
Output:
Number: 12
Enter data: 12.43
You entered: 12.43
Explanation of Program:
In this program, two data members data1 and data2 and two member
function int_data() and float_data() are defined under temp class. Two
objects obj1 and obj2 of that class are declared. Function int_data() for the obj1 is
executed using code obj1.int_data(12);, which sets 12 to the data1 of object obj1.
Then, function float_data() for the object obj2 is executed which takes data from
user; stores it in data2 of obj2 and returns it to the calling function.
Note: In this program, data2 for object obj1 and data1 for object obj2 is not used and
contains garbage value.
CHAPTER-2
2.1. FUNCTION OVERLOADING:
You can have multiple definitions for the same function name in the same scope.
The definition of the function must differ from each other by the types and/or the number of
arguments in the argument list. You can not overload function declarations that differ only by
return type.
Following is the example where same function print() is being used to print different data
types:
#include <iostream>
using namespace std;
class printData
{
public:
void print(int i) {
cout << "Printing int: " << i << endl;
}
void print(double f) {
cout << "Printing float: " << f << endl;
}
void print(char* c) {
cout << "Printing character: " << c << endl;
}
};
int main(void)
{
printData pd;
// Call print to print integer
pd.print(5);
// Call print to print float
pd.print(500.263);
// Call print to print character
pd.print("Hello C++");
return 0;
}
When the above code is compiled and executed, it produces the following result:
Printing int: 5
breadth = bre;
}
void setHeight( double hei )
{
height = hei;
}
// Overload + operator to add two Box objects.
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
// Main function for the program
int main( )
{
Box Box1;
// Declare Box1 of type Box
Box Box2;
// Declare Box2 of type Box
Box Box3;
// Declare Box3 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();
cout << "Volume of Box1 : " << volume <<endl;
// volume of box 2
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;
// Add two object as follows:
Box3 = Box1 + Box2;
// volume of box 3
volume = Box3.getVolume();
cout << "Volume of Box3 : " << 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
Volume of Box3 : 5400
Iterators are a design pattern that were popularized in the seminal book "Design Patterns"
by Gamma et al. It's a pattern to iterate over the content of a container class. Unlike using
a for-loop an iterator is an instance of a class that points to a member of the container and
gives you an unified interface to traverse the container as well as accessing the members.
Take look at this example:
// Instanciate template QList with type int
QList<int> myList;
// put some ints into myList
// Copyconstruct iterator that points to the
// first member of the list.
QList<int>::iterator i = myList.begin();
// Iterate through the list
while (i != myList.end()) {
std::cout << *i << std::endl;
i++;
}
In this C++ example I'm instantating a template QList with type int. QList a container class
that stores a list of objects. In this example we will use it to store integers.
Then I create an iterator i to traverse through the list. myList.begin() returns an iterator
that points to the first element of the list. We can compare the iterator with another
iterator myList.end()that points after the last element of the list. If both iterators are the
same we know that we have passed the last elment. In the loop we're printing the element by
accessing it with *i and go to the next element with i++.
Note that in this example * and ++ are overloaded operators and reimplemented by the
iterator class. In a programming language without operator overloading there could be
methods like i.element() or i.next() that do the same task. It's important to see that i is
not a pointer but a whole class that just mimics the behaviour of a pointer.
What's the benefit of iterators? They provide a unified way to access the members of a
container class, completely indepented on how the container class is implemented internally.
No matter if your want to traverse a list, map or tree, the iterator classes (should) always
work the same way.
.
.
}
Here, type is the placeholder type name, which will be specified when a class is instantiated.
You can define more than one generic data type by using a comma-separated list.
Following is the example to define class Stack<> and implement generic methods to push
and pop the elements from the stack:
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
using namespace std;
template <class T>
class Stack {
private:
vector<T> elems;
// elements
public:
void push(T const&); // push element
void pop();
// pop element
T top() const;
// return top element
bool empty() const{
// return true if empty.
return elems.empty();
}
};
template <class T>
void Stack<T>::push (T const& elem)
{
// append copy of passed element
elems.push_back(elem);
}
template <class T>
void Stack<T>::pop ()
{
if (elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
// remove last element
elems.pop_back();
}
}
When the above code is compiled and executed, it produces the following result:
Total area: 35
Access Control and Inheritance:
A derived class can access all the non-private members of its base class. Thus base-class
members that should not be accessible to the member functions of derived classes should be
declared private in the base class.
We can summarize the different access types according to who can access them in the
following way:
Access
Public
protected
Private
Same class
Yes
Yes
Yes
Derived classes
Yes
Yes
No
Outside classes
Yes
No
No
A derived class inherits all base class methods with the following exceptions:
Public Inheritance: When deriving a class from a public base class, public members
of the base class become public members of the derived class and protected members of the
base class become protected members of the derived class. A base class's private members
are never accessible directly from a derived class, but can be accessed through calls to
the public andprotected members of the base class.
Protected
Inheritance: When
deriving
from
a protected base
class, public and protectedmembers of the base class become protected members of the
derived class.
Private
Inheritance: When
deriving
from
a private base
class, public and protected members of the base class become private members of the
derived class.
Multiple Inheritances:
A C++ class can inherit members from more than one class and here is the extended syntax:
class derived-class: access baseA, access baseB....
Where access is one of public, protected, or private and would be given for every base class
and they will be separated by comma as shown above. Let us try the following example:
#include <iostream>
using namespace std;
// Base class Shape
class Shape
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// Base class PaintCost
class PaintCost
{
public:
int getCost(int area)
{
CHAPTER 3
For example, we might say "this algorithm takes n2 time," where n is the number of items in
the input. Or we might say "this algorithm takes constant extra space," because the amount of
extra memory needed doesn't vary with the number of items processed.
For both time and space, we are interested in the asymptotic complexity of the algorithm:
When n (the number of items of input) goes to infinity, what happens to the performance of
the algorithm?
comments
initial
i=0 |
0
3
9
6
i=1 |
0
1
9
6
i=2 |
0
1
3
6
i=3 |
0
1
3
4
i=4 |
0
1
3
4
i=5 |
0
1
3
4
Here is a simple implementation in C:
1
3
9
9
6
6
7
7
7
7
7
7
4
4
4
6
9
9
swap 0,4
swap 1,3
swap 3, 9
swap 6, 4
swap 9, 6
(done)
For this example, the amount of space needed is clearly dominated by the memory consumed
by the array, so we don't have to worry about it; if we can store the array, we can sort it. That
is, it takes constant extra space.
So we are mainly interested in the amount of time the algorithm takes. One approach is to
count the number of array accesses made during the execution of the algorithm; since each
array access takes a certain (small) amount of time related to the hardware, this count is
proportional to the time the algorithm takes.
We will end up with a function in terms of n that gives us the number of array accesses for
the algorithm. We'll call this function T(n), for Time.
T(n) is the total number of accesses made from the beginning of selection_sort until the
end. selection_sort itself simply calls swap and find_min_index as i goes from 0 to n-1, so
T(n) =
(n-2 because the for loop goes from 0 up to but not including n-1). (Note: for those not
familiar with Sigma notation, that nasty looking formula above just means "the sum, as we
let i go from 0 to n-2, of the time for swap plus the time for find_min_index (v, i, n).)
The swap function makes four accesses to the array, so the function is now
T(n) =
If we look at find_min_index, we see it does two array accesses for each iteration through
the for loop, and it does the for loop n - i - 1 times:
T(n) =
[ 4 + 2 (n - i - 1)] .
i.
(everything times n-1 because we go from 0 to n-2, i.e., n-1 times). Remembering that the
sum of i as i goes from 0 to n is (n(n+1))/2, then substituting in n-2 and cancelling out the 2's:
T(n) = 4(n-1) + 2n(n-1) - 2(n-1) - ((n-2)(n-1)).
and to make a long story short,
T(n) = n2 + 3n - 4 .
So this function gives us the number of array accesses selection_sort makes for a given array
size, and thus an idea of the amount of time it takes. There are other factors affecting the
performance, for instance the loop overhead, other processes running on the system, and the
fact that access time to memory is not really a constant. But this kind of analysis gives you a
good idea of the amount of time you'll spend waiting, and allows you to compare this
algorithms to other algorithms that have been analyzed in a similar way.
Another algorithm used for sorting is called merge sort. The details are somewhat more
complicated and will be covered later in the course, but for now it's sufficient to state that a
certain C implementation takes Tm(n) = 8n log n memory accesses to sort n elements. Let's
look at a table of T(n) vs. Tm(n):
n
T(n)
Tm(n)
---------2
6
11
3
14
26
4
24
44
5
36
64
6
50
86
7
66
108
8
84
133
9
104
158
10
126
184
11
150
211
12
176
238
13
204
266
14
234
295
15
266
324
16
300
354
17
336
385
18
374
416
19
414
447
20
456
479
T(n) seems to outperform Tm(n) here, so at first glance one might think selection sort is better
than merge sort. But if we extend the table:
n
--20
21
T(n)
---456
500
Tm(n)
----479
511
22
546
544
23
594
576
24
644
610
25
696
643
26
750
677
27
806
711
28
864
746
29
924
781
30
986
816
we see that merge sort starts to take a little less time than selection sort for larger values of n.
If we extend the table to large values:
n
T(n)
Tm(n)
---------100
10,296
3,684
1,000
1,002,996
55,262
10,000 100,029,996
736,827
100,000 10,000,299,996 9,210,340
1,000,000
1,000,002,999,996
110,524,084
10,000,000
100,000,029,999,996 1,289,447,652
we see that merge sort does much better than selection sort. To put this in perspective, recall
that a typical memory access is done on the order of nanoseconds, or billionths of a second.
Selection sort on ten million items takes roughly 100 trillion accesses; if each one takes ten
nanoseconds (an optimistic assumption based on 1998 hardware) it will take 1,000,000
seconds, or about 11 and a half days to complete. Merge sort, with a "mere" 1.2 billion
accesses, will be done in 12 seconds. For a billion elements, selection sort takes almost
32,000 years, while merge sort takes about 37 minutes. And, assuming a large enough RAM
size, a trillion elements will take selection sort 300 million years, while merge sort will take
32 days. Since computer hardware is not resilient to the large asteroids that hit our planet
roughly once every 100 million years causing mass extinctions, selection sort is not feasible
for this task. (Note: you will notice as you study CS that computer scientists like to put things
in astronomical and geological terms when trying to show an approach is the wrong one. Just
humor them.)
ADT in lists in C++ or sequence is an abstract data type that implements a finite ordered
collection of values, where the same value may occur more than once. An instance of a list is
a computer representation of the mathematical concept of a finite sequence; the (potentially)
infinite analog of a list is a stream. Lists are a basic example of containers, as they contain
other values. Each instance of a value in the list is usually called an item, entry, or element of
the list; if the same value occurs multiple times, each occurrence is considered a distinct item.
Lists are distinguished from arrays in that lists only allow sequential access, while arrays
allow random access.
C++ Classes
Encapsulation (used to refer to one of two related but distinct notions, and sometimes to
the combination) combines an ADTs data with its operations to form an object
1.
2.
3.
4.
5.
6.
C++ Namespaces- AS mechanism for logically grouping declarations and definitions into a
common.
_______
_________
\
/
\
values in
\/
/
\/
| ----- |
values out
|
|
| ----- |
|
|
| ----- |
|
|
|
|
---------Think of a stack of newspapers or trays in a cafeteria. The only item that can be taken out (or
even seen) is the most recently added (or top) item; a Stack is a Last-In-First-Out (LIFO)
abstract data type.
/
Description
return true iff the Stack is empty
remove and return the item from the top of the Stack (error
if the Stack is empty)
E peek()
return the item that is on the top of the Stack, but do not
remove it (error if the Stack is empty)
Queues:
The conceptual picture of a Queue ADT is something like this:
-----------------items in the queue
----> values out
-----------------^
^
|
|
this is the rear of
this is the front of
the queue
the queue
values in ---->
Think of people standing in line. A Queue is a First-In-First-Out (FIFO) abstract data type.
Items can only be added at the rear of the queue and the only item that can be removed is the
one at the front of the queue.
Here are the Queue ADT operations:
Operation
Description
E dequeue()
remove and return the item from the front of the Queue (error if
the Queue is empty)
Implementing Stacks:
The Stack ADT is very similar to the List ADT; therefore, their implementations are also
quite similar.
Array Implementation:
Below is the definition of the ArrayStack class, using an array to store the items in the stack;
note that we include a static final variable INITSIZE, to be used by
the ArrayStack constructor as the initial size of the array (the same thing was done for
the ArrayList class).
public class ArrayStack<E> implements StackADT<E> {
// *** fields ***
private static final int INITSIZE = 10; // initial array size
private E[] items; // the items in the stack
private int numItems; // the number of items in the stack
// *** constructor ***
public ArrayStack() { ... }
// *** required StackADT methods ***
// add items