01 Intro-Cpp

Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1of 159

Introduction To C++

1
CENG 213
Instructor: Yusuf Sahillioğlu
Office: B107
Email: ys@ceng.metu.edu.tr
Lecture Hours:
• Tue
Web Page: http://user.ceng.metu.edu.tr/~ys/ceng707-dsa/
Follow odtuclass as well.
Playlist:
https://www.youtube.com/playlist?list=PLamOUbhy_opKnRsYs
OPvkw3lBEiaL0VjY

2
Course Description
Course Objectives: To introduce abstract concepts for data
organization and manipulation, to show how these concepts
are useful in problem solving. 

Text Book and References


1. Mark Allen Weiss, Data Structures and Algorithm Analysis in
C++ (3rd ed.), Addison Wesley, 2006 (Current Textbook).
2. M. T. Goodrich, R. Tamassia and D. Mount, Data Structures
and Algorithms in C++, John Wiley & Sons, 2004 Mark Allen
Weiss, Data Structures and Problem Solving Using C++, 2nd
ed., Addison Wesley 2000
3. Sartaj Sahni, Data Structures, Algorithms, and Applications in
C++, McGraw Hill, 1998.
4. H.M. Deitel, P.J. Deitel, How To Program C++ and Java by
Prentice-Hall, 2001.
5. The C++ Tutorial: http://www.learncpp.com/
3
Grading
• Midterm: 30%
• Final Exam: 35%
• Programming Assignments: 30% (2 x 15%)
• Participation in Class: 5%

• All assignments are to be your own work. No group projects or


assignments are allowed.
• Exams are closed-book.

4
Course Outline
• Overview of object-oriented programming with
C++ [chapter 1]
• Algorithm analysis [chapter 2]
• Sorting [chapter 7]
• Lists, stacks, queues [chapter 3]
• Trees [chapter 4]
• Priority queues [chapter 6]
• Hashing [chapter 5]
• Graphs [chapter 9]

5
Motivational Example # 1
• All these structures are there to efficiently store
and process data
• Even a simple data structure you already know
may be very useful if used in the right context
• Store nxn entries of an N-matrix in an array
– Huge profit considering n=1 million, usual case
– Column 1, column n, diagonal (remaining)
– Size of the compact array A?

6
Motivational Example # 1
• All these structures are there to efficiently store
and process data
• Even a simple data structure you already know
may be very useful if used in the right context
• Store nxn entries of an N-matrix in an array
– Huge profit considering n=1 million, usual case
– Column 1, column n, diagonal (remaining)
– 3n-2
– Implement set(i,j,v) to update A[] accordingly

7
Motivational Example # 1
• All these structures are there to efficiently store
and process data
• Even a simple data structure you already know
may be very useful if used in the right context
• Store nxn entries of an N-matrix in an array
– Huge profit considering n=1 million, usual case
– Column 1, column n, diagonal (remaining)
– 3n-2
– if (j==1) A[i] = v;
else if (j==n) A[n+i] = v;
else if (i==j) A[2n+i-1] = v;
8
Motivational Example # 2
• All these structures are there to efficiently store
and process data
• We did 2D array  1D array.
• Now do 1D array  auxiliary 1D array.
• Problem: find the sum of a subarray quickly:

sumq(3, 6) = 19

9
Motivational Example # 2
• All these structures are there to efficiently store
and process data
• We did 2D array  1D array.
• Now do 1D array  auxiliary 1D array.
• Problem: find the sum of a subarray quickly:

sumq(3, 6) = 19

Slower way 
10
Motivational Example # 2
• All these structures are there to efficiently store and
process data
• We did 2D array  1D array.
• Now do 1D array  auxiliary 1D array.
• Problem: find the sum of a subarray quickly:

sumq(3, 6) = 19
Auxiliary Prefix Sum Array:
Cooler/faster way 
11
Motivational Example # 2
• All these structures are there to efficiently store and
process data
• We did 2D array  1D array.
• Now do 1D array  auxiliary 1D array.
• Problem: find the sum of a subarray quickly:

sumq(3, 6) = 19
Auxiliary Prefix Sum Array:
Cooler/faster way 
sumq(0,6) - sumq(0,2) = 27 – 8.
12
Motivational Example # 2
• All these structures are there to efficiently store and
process data
• We did 2D array  1D array.
• Now do 1D array  auxiliary 1D array.
• Problem: find the sum of a subarray quickly.
• How to compute Prefix Sum Array P?

Array:

P:
13
Motivational Example # 2
• All these structures are there to efficiently store
and process data
• We did 2D array  1D array.
• Now do 1D array  auxiliary 1D array.
• Problem: find the sum of a subarray quickly.
• How to compute Prefix Sum Array P?
– Dead simple application of dynamic programming:
• P[0]=A[0]; for(i=1 to n-1) P[i]=P[i-1]+A[i];

14
Motivational Example # 2
• All these structures are there to efficiently store
and process data
• We did 2D array  1D array.
• Now do 2D array  auxiliary 1D array.

15
Motivational Example # 2
• All these structures are there to efficiently store and process data
• We did 2D array  1D array.
• Now do 2D array  auxiliary 1D array.

• Sum of gray subarray: S(A) - S(B) - S(C) + S(D) where S(X) is the sum of values in a
rectangular subarray from the upperleft corner to the position of X.

16
Programming in C++
• C++
– Improves on many of C's features
– Has object-oriented capabilities
• Increases software quality and reusability
– Developed by Bjarne Stroustrup at Bell Labs
• Called "C with classes"
• C++ (increment operator) - enhanced version of C
– Superset of C
• Can use a C++ compiler to compile C programs
• Gradually evolve the C programs to C++

17
Object Oriented Programming
 The emphasis is on creating a set of tools which can be
used cleanly, with a minimum knowledge about
implementation in the user’s driver files. The following
concepts are relevant to accomplishing clean interface:
1. Data Abstraction
– 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
• TV: you can turn on and off, change the channel, adjust the volume, 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.
• sort: you can sort an array with this C++ call, BUT you do not know the algorithm.

– In C++, we use classes to define our own abstract data types (ADT).

18
Object Oriented Programming
1. Data Abstraction
– Example: 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.

19
Object Oriented Programming
2. Information hiding
– Example: Restrict access to data so that
it can be manipulated only in
authorized ways. Separate
class declarations from
implementation (e.g. public,
private in C++).

20
Object Oriented Programming
3. Encapsulation
– bundling of data with the methods (or other functions) operating
on that data (implementation of the methods).

21
C++ Techniques
 Relevant techniques include:
1. C++ classes, with private and public members
2. Function and operator name overloading to give
"natural" function calls
3. Templates to allow the same code to be used on
a variety of different data types
4. A clean built-in I/O interface, which itself
involves overloading the input and output
operators
 Learning these techniques is much of what C++
is all about.
22
A Basic C++ Program
#include <iostream> //input/output
#include <math.h> //usual C lib header file for math

using namespace std;

int main()
{
float x;

cout << "Enter a real number: " << endl;


cin >> x; //scanf("%f", &x); in C

cout << "The square root of " << x << " is: "
<< sqrt(x) << endl; //see comments part
}
23
A Basic C++ Program
cout << "Enter a real number: " << endl;

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. //Data Abstraction

In C++, all I/O is done by classes. A class is set up to handle input and output
streams. Output to the screen is handled by the stream with standard name
cout. This is a variable of class ostream. Similarly for cin.

24
A Basic C++ Program
// second C++ program

#include <iostream>

using namespace std;

int main(){
int a=23;
int b=34;

cout << "Enter two integers:" << endl;


cin >> a >> b;
cout << endl;

cout << “a + b =“ << a+b << endl;


return 0;
}

25
A Basic C++ Program
// third C++ program

#include <iostream>
#include <iomanip>
using namespace std;

int main(){
double a=15.2;
double b=34.3434343;

cout << fixed << showpoint;


cout << setprecision(2); //2 digits after the dot
cout << setw(6) << a << endl;
cout << setw(7) << b << endl;

return 0;
}

26
A Basic C++ Program
// third C++ program

#include <iostream>
#include <iomanip>
using namespace std;

int main(){
double a=15.2;
double b=34.3434343;

cout << fixed << showpoint;


cout << setprecision(2); //2 digits after the dot
cout << setw(6) << a << endl; //15.20
cout << setw(7) << b << endl; //34.34

return 0;
}

27
Classes and Objects
• Class: a type definition that includes both
– data properties, and
– operations permitted on that data
• Object: a variable that
– is declared to be of some Class
– therefore includes both data and operations for that
class
• Appropriate usage:
“A variable is an instance of a type.”
“An object is an instance of a class.”

28
Basic Class Syntax
• A class in C++ consists of its members.
– A member can be either data or functions.
• The functions are called member functions
(or methods)
• Each instance of a class is an object.
– Each object contains the data components
specified in class.
– Methods/functions are used to act on an
object.
29
Class syntax - Example
// A class for simulating an integer memory cell

class IntCell
{
public:
IntCell( )
{ storedValue = 0; }
constructors
IntCell(int initialValue )
{ storedValue = initialValue;}

int read( )
{ return storedValue; }

void write( int x )


{ storedValue = x;}

private:
int storedValue;
};

30
Class Members
• Public member is visible to all routines and may
be accessed by any method in any class.
• Private member is not visible to non-class
routines and may be accessed only by methods in its
class.
• Typically,
– Data members are declared private
– Methods are made public
• Restricting access is known as information hiding.

31
Class Members

32
Constructors
• A constructor is a method that executes when an
object of a class is declared and sets the initial state
of the new object.
• A constructor
– has the same name with the class,
– no return type
– has zero or more parameters (the constructor
without an argument is the default constructor)
• There may be more than one constructor defined
for a class.
• If no constructor is explicitly defined, one that
initializes the data members using language defaults
is automatically generated.
33
Extra Constructor Syntax
// A class for simulating an integer memory cell

class IntCell
{
public: Single
IntCell( int initialValue = 0 ) constructor
: storedValue( initialValue) { } (instead of
two)
int read( ) const
{ return storedValue; }

void write( int x )


{ storedValue = x; }
private:
int storedValue;
};

34
Object Declaration
• In C++, an object is declared just like a
primitive type.
#include <iostream>
using namespace std;
#include "IntCell.h"

int main()
{
//correct declarations
IntCell m1;
IntCell m2 ( 12 );
IntCell *m3;

// incorrect declaration
Intcell m4(); // this is a function declaration,
// not an object
35
Object use in driver program
// program continues

m1.write(44);
m2.write(m2.read() +1);
cout << m1.read() << " " << m2.read() << endl;
m3 = new IntCell;
cout << "m3 = " << m3->read() << endl;
return 0;
}

36
Example: Class Time
class Time {
public:
Time( int = 0, int = 0, int = 0 ); //default
//constructor
void setTime( int, int, int ); //set hr, min,sec
void printMilitary(); // print am/pm format
void printStandard(); // print standard format

private:
int hour;
int minute;
int second;
};

37
Declaring Time Objects
// Note that implementation of class Time not given
// here.

int main(){
Time t1, // all arguments defaulted
t2(2), // min. and sec. defaulted
t3(21, 34), // second defaulted
t4(12, 25, 42); // all values specified
. . .
}

38
Class Interface and Implementation
• In C++, separating the class interface from its
implementation is common.
– The interface remains the same for a long time.
– The implementations can be modified independently.
– The writers of other classes and modules have to know
the interfaces of classes only.
• The interface lists the class and its members (data
and function prototypes) and describes what can be
done to an object.
• The implementation is the C++ code for the
member functions.
39
Separation of Interface and Implementation
• It is a good programming practice for large-scale
projects to put the interface and implementation
of classes in different files.
• For small amount of coding it may not matter.
• Header File: contains the interface of a class.
Usually ends with .h (an include file)
• Source-code file: contains the implementation of
a class. Usually ends with .cpp (.cc or .C)
• .cpp file includes the .h file with the preprocessor command
#include.
» Example: #include ”myclass.h”

40
Separation of Interface and Implementation

• A big complicated project will have files that


contain other files.
– There is a danger that an include file (.h file) might be
read more than once during the compilation process.
• It should be read only once to let the compiler learn the
definition of the classes.
• To prevent a .h file to be read multiple times, we
use preprocessor commands #ifndef and
#define in the following way.

41
Class Interface
#ifndef _IntCell_H_
#define _IntCell_H_

class IntCell
{
public:
IntCell( int initialValue = 0 );
int read( ) const;
void write( int x );
private:
int storedValue;
};
#endif
IntCell class Interface in the file IntCell.h

42
Class Implementation
#include <iostream>
#include “IntCell.h”
using std::cout;

//Construct the IntCell with initialValue


IntCell::IntCell( int initialValue)
: storedValue( initialValue) {}

//Return the stored value.


int IntCell::read( ) const
{ Scope operator:
return storedValue;
} ClassName :: member
//Store x.
void IntCell::write( int x )
{
storedValue = x;
}
IntCell class implementation in file IntCell.cpp
43
A driver program
#include <iostream>
#include “IntCell.h”
using std::cout;
using std::endl;

int main()
{
IntCell m; // or IntCell m(0);

m.write (5);
cout << “Cell content : “ << m.read() << endl;

return 0;
}

A program that uses IntCell in file TestIntCell.cpp

44
Destructors
• Member function of class
• Performs termination housekeeping before the
system reclaims the object’s memory
• Complement of the constructor
• Name is tilde (~) followed by the class name
• E.g. ~IntCell( );
~ Time( );
• Receives no parameters, returns no value
• One destructor per class

45
Destructors
• A destructor is a special member function of a
class that is executed whenever an object of it's
class goes out of scope or whenever the delete
expression is applied to a pointer to the object of
that class.

46
Destructor Example
class IntCell{
public:
IntCell(int initialValue=0)
{ storedValue = new int (initialValue);}

~IntCell()
{ delete storedValue; }

int read( ) const


{ return *storedValue; }

void write( int x ) { *storedValue = x; }


private:
int *storedValue;
}

47
Destructor Example

48
When are Constructors and Destructors Called
• Global scope objects
• Constructors called before any other function (including main)
• Destructors called when main terminates (or exit function
called)
• Automatic local objects
• Constructors called when objects defined
• Destructors called when objects leave scope (when the block
in which they are defined is exited)
• static local objects
• Constructors called when execution reaches the point where
the objects are defined
• Destructors called when main terminates or the exit function is
called

49
Accessor and Modifier Functions

• A method that examines but does not


change the state of its object is an accessor.
– Accessor function headings end with the word
const
• A member function that changes the state
of an object is a mutator.

50
Another Example: Complex Class
#ifndef _Complex_H
#define _Complex_H

using namespace std;


class Complex
{
float re, im; // by default private
public:
Complex(float x = 0, float y = 0)
: re(x), im(y) { }

Complex operator*(Complex rhs) const;


float modulus() const;
void print() const;
};

#endif

51
Complex class Interface in the file Complex.h
Implementation of Complex Class
#include <iostream>
#include <cmath>
#include "Complex.h"
Complex Complex::operator*(Complex rhs) const
{
Complex prod;
prod.re = (re*rhs.re - im*rhs.im);
prod.im = (re*rhs.im + im*rhs.re);
return prod;
}
float Complex::modulus() const
{
return sqrt(re*re + im*im);
}
void Complex::print() const
{
std::cout << "(" << re <<"," << im << ")" << std::endl;
}

Complex class implementation in file Complex.cpp 52


Using the class in a Driver File
#include <iostream>
#include "Complex.h"
int main()
{
Complex c1, c2(1), c3(1,2);
float x;
// overloaded * operator!!
c1 = c2 * c3 * c2;

// mistake! The compiler will stop here, since the


// re and im parts are private.
x = sqrt(c1.re*c1.re + c1.im*c1.im);

// OK. Now we use an authorized public function


x = c1.modulus();

c1.print();
return 0;
}
53
A program that uses Complex in file TestComplex.cpp
Function Overloading
• Function overloading:
– Functions with same name and different parameters
– Overloaded functions performs similar tasks
• Function to square ints and function to square floats
int square( int x) {return x * x;}
float square(float x) { return x * x; }
– Program chooses function by signature
• Signature determined by function name and parameter types
• Type safe linkage - ensures proper overloaded function called

54
Function Overloading
• Function overloading:
– Functions with same name and different parameters
– Overloaded functions performs similar tasks

– Program chooses function by signature


• Signature determined by function name and parameter types

55
// Using overloaded functions
#include <iostream>
using std::cout;
using std::endl;
int square( int x ) { return x * x; }
double square( double y ) { return y * y; }

int main()
{
cout << "The square of integer 7 is " << square( 7 )
<< "\nThe square of double 7.5 is " << square( 7.5 )
<< endl;

return 0;
}

56
Overloaded Operators
• An operator with more than one meaning is said to be
overloaded.
2 + 3 3.1 + 3.2  + is an overloaded operator

• To enable a particular operator to operate correctly on


instances of a class, we may define a new meaning for
the operator.
 we may overload it

Ex: operator* from Complex and Vector classes

57
Operator Overloading
• Format
– Write function definition as normal
– Function name is keyword operator followed by the
symbol for the operator being overloaded.
– operator+ would be used to overload the addition
operator (+)
• No new operators can be created
– Use only existing operators
• Built-in types
– You cannot change how two integers are added

58
Overloaded Operators -- Example
What if we want to multiply a complex number with a scalar? Define
another function with the same name but different parameters.

class Complex
{
...

Complex operator*(Complex rhs) const;


Complex operator*(float k) const;

...
};

59
Implementation of Complex Class
Complex Complex::operator*(Complex rhs) const
{
Complex prod;
prod.re = (re*rhs.re - im*rhs.im);
prod.im = (re*rhs.im + im*rhs.re);
return prod;
}

Complex Complex::operator*(float k) const


{
Complex prod;
prod.re = re * k;
prod.im = im * k;
return prod;
}

Complex class implementation in file Complex.cpp 60


Using the class in a Driver File
#include <iostream>
#include "Complex.h"

int main()
{
Complex c1, c2(1), c3(1,2);

c1 = c2 * c3 * c2;
c1.print();

c1 = c1 * 5; // translated to c1.operator*(5)
c1.print();

// How about this?


c1 = 5 * c1;

return 0;
}
61
A program that uses Complex in file TestComplex.cpp
Using the class in a Driver File
#include <iostream>
#include "Complex.h"

int main()
{
Complex c1, c2(1), c3(1,2);

c1 = c2 * c3 * c2;
c1.print();

c1 = c1 * 5; // translated to c1.operator*(5)
c1.print();

// How about this?


c1 = 5 * c1; // CANNOT translate to 5.operator*(c1)

return 0;
}
62
A program that uses Complex in file TestComplex.cpp
Putting the Scalar to the Left
To support multiplying with a scalar on the left, we must define a new
function that is outside the class scope.
Complex operator*(float k, Complex c)
{
Complex prod;
prod.re = k * re; // Compile Error: cannot access re
prod.im = k * im; // Compile Error: cannot access im
return prod;
}

Note that this function has access errors: an outside function cannot
access the private members of a class! We can solve this in two ways.
63
Solution 1: Setter/Getter Functions

class Complex Recall the old class:


{
...

public:
// add the following functions to the class

void setReal(float x) { re = x; }
void setImag(float x) { im = x; }
float getReal() const { return re; }
float getImag() const { return im; }

...
};
64
Solution 1: Setter/Getter Functions

Complex operator*(float k, Complex c)


{
Complex prod;
prod.setReal(k * c.getReal());
prod.setImag(k * c.getImag());
return prod;
}

65
Solution 2: Friend Functions
Declare the outside function as the friend of this class. It can then
access the private members of the class.
class Complex
{
...

friend Complex operator*(float k, Complex rhs);

...
};

66
Solution 2: Friend Functions

Complex operator*(float k, Complex c)


{
Complex prod;
prod.re = k * re; // Now it is ok
prod.im = k * im; // Now it is ok
return prod;
}

Note that the “friend” keyword is not used here. It is only used inside the class (see the previous slide).

67
Friend Classes
A class may declare another class as a friend as well. In that case all
member functions of the “befriended” class can access the private
members of its friend class
class A
{
...
};

class B
{
...
friend A;
};

“A” can access private members of “B” (but not vice versa!!!)

68
69
Exercise 1
• What is the output from the following loops?
a)
for ( int i=0; i < 5 ; i++) {
cout << i;
}
cout<<endl;
b)
for ( int i = 0; i < 10 ; i += 2) {
cout << i << endl ;
}

70
Exercise 2
• What is the output?
int i = 24 ;
while ( i > 0) {
cout << i << endl ;
i /= 2 ;
}

71
Pointers
• Pointer fun video: https://youtu.be/i49_SNt4yfk
• Normal variables contain a specific value (direct
reference)
int count = 7;
count
 

• Pointer variables contain memory addresses as their


values
int * countPtr;
countPtr
count
countPtr = & count;
7

72
Pointer Variable Declarations and Initialization
• A pointer declaration takes the following form:
type *identifier;
e.g.
int *myPtr;
– Declares a pointer to an int (pointer of type int *)

• We can declare pointers to any data type.


e.g. float *fptr; char *cptr;
• We usually initialize pointers to nullptr
• nullptr – points to nothing
e.g.
myPtr = nullptr;
73
Pointer Operators
• & (address operator) - Returns the address of operand
int y = 5;
int *yPtr;
yPtr = &y; // yPtr gets address of y
– yPtr “points to” y

y yptr y
5 500000 600000 600000 5
yPtr

Address of y
is value of
yptr

74
Pointer Operators
• * (indirection/dereferencing operator)
– Returns an alias of what its operand points to
– *yptr returns y (because yptr points to y)
– * can be used for assignment
*yptr = 7; // changes y to 7

• * and & are inverses


– They cancel each other out

75
int rate;
int *p_rate;

rate = 500;
p_rate = &rate;

1000 1004 1008 1012


Memory 1008 500

p_rate rate

/* Print the values */


cout <<"rate = "<< rate << endl; /* direct access */
cout <<"rate = "<< *p_rate << endl; /* indirect access */

76
Exercise 3
int a, b, *p;

a = b = 7;
p = &a;
// 1st print statement
cout << "*p = " << *p << endl;

*p = 3;
// 2nd print statement
cout << "a = " << a << endl;

p = &b;

*p = 2 * *p - a;

// 3rd print statement


cout << "b = " << b << endl;
77
Passing parameters to functions by value

void SetToZero (int var)


{
var = 0;
}

• You would make the following call:

SetToZero(x);

• This function has no effect whatever to change the value of x.


• This is referred to as call-by-value.
78
Passing parameters by reference
void SetToZero (int *ip)
{
*ip = 0;
}

• You would make the following call:

SetToZero(&x);

This is referred to as call-by-reference.

79
/* Swapping arguments (incorrect version) */
#include <iostream>

void swap (int p, int q)


{
int tmp;

tmp = p;
p = q;
q = tmp;
}

int main (void)


{
int a = 3;
int b = 7;
cout << a << b << endl;
swap(a,b);
cout << a << b << endl;
return 0;
}
80
/* Swapping arguments (correct version) */
#include <iostream>

void swap (int *p, int *q)


{
int tmp;

tmp = *p; p q
*p = *q;
*q = tmp;
}

int main (void)


{
a b
int a = 3; 3 7
int b = 7;
cout << a << b << endl;
swap(&a, &b);
cout << a << b << endl;
return 0;
}
81
References
• References are a type of C++ variable that act
as an alias to another variable.
• A reference variable acts just like the original
variable it is referencing.
• References are declared by using an
ampersand (&) between the reference type
and the variable name.

82
Example
int n = 5, m = 6; You cannot declare a
int &rn = n; reference without
giving a value.
n = 6;
rn = 7,
cout << n << rn << m << endl;
rn = m ;
cout << n << rn << m << endl;

83
/* Swapping arguments - with reference variables*/
#include <iostream>

void swap (int &p, int &q)


{
int tmp;

tmp = p; p q
p = q;
q = tmp;
}
int main (void)
{ a b
int a = 3; 3 7
int b = 7;
cout << a << b << endl;
swap(a, b);
cout << a << b << endl;
return 0;
}
84
Exercise 4
• What is the output?
void fun1(int *a, int b){
b = b - 1;
*a = *a + b;
cout << *a << " " << b << endl;
}
int main(){
int a=3, b=3;
fun1(&a,b);
cout << a << " " << b << endl;
}

85
Exercise 5
What is the output?
void fun2(int &a, int b){
a = a * 2;
b = a + b;
cout << a << “ “ << b << endl;
}
int main(){
int x=3, y=5;
fun2(x,y);
cout << x << “ “ << y << endl;
}

86
Classes and Objects
• Class: a type definition that includes both
– data properties, and
– operations permitted on that data
• Object: a variable that
– is declared to be of some Class
– therefore includes both data and operations for that
data
• Appropriate usage:
“A variable is an instance of a type.”
“An object is an instance of a class.”

87
Basic Class Syntax
• A class in C++ consists of its members.
– A member can be either data or functions.
• The functions are called member functions
(or methods)
• Each instance of a class is an object.
– Each object contains the data components
specified in class.
– Methods are used to act on an object.

88
Class syntax - Example
// A class for simulating an integer memory cell

class IntCell
{
public:
IntCell( )
{ storedValue = 0; }
constructors
IntCell(int initialValue )
{ storedValue = initialValue;}

int read( )
{ return storedValue; }

void write( int x )


{ storedValue = x;}

private:
int storedValue;
};

89
Object declaration and use
• In C++, an object is declared just like a primitive type.
#include <iostream>
using namespace std;
#include "IntCell.h"

int main()
{
//correct declarations
IntCell m1;
IntCell m2 (8);
IntCell *m3;

90
Object use in driver program
// program continues

m1.write(44);
m2.write(m2.read() +1);
cout << m1.read() << " " << m2.read() << endl;
m3 = new IntCell;
cout << "m3 = " << m3->read() << endl;
return 0;
}

91
Dynamic Memory Allocation
• new and delete
– new - automatically creates object of proper size, calls
constructor, returns pointer of the correct type
– delete - destroys object and frees space
– You can use them in a similar way to malloc and free in C.
• Syntax:
– TypeName *typeNamePtr;
– typeNamePtr = new TypeName;
– new creates TypeName object, returns pointer (which typeNamePtr
is set equal to)
– delete typeNamePtr;
– Calls destructor for TypeName object and frees memory

92
Examples
// declare a ptr to user-defined data type
IntCell *ptr1;
int *ptr2;

// dynamically allocate space for an IntCell;


// initialize values; return pointer and assign
// to ptr1
ptr1 = new IntCell(5);

// similar for int:


ptr2 = new int(2);
// free up the memory that ptr1 points to
delete ptr1;

93
// dynamically allocate array of 23
// IntCell slots
// each will be initialized to 0
ptr1 = new IntCell[23];

// similar for int


ptr2 = new int[12];

// free up the dynamically allocated array


delete [] ptr1;

94
References
• References are a type of C++ variable that act
as an alias to another variable.
• A reference variable acts just like the original
variable it is referencing.
• References are declared by using an
ampersand (&) between the reference type
and the variable name.

95
Example
int n = 5, m = 6; You cannot declare a
int &rn = n; reference without
giving a value.
n = 6;
rn = 7,
cout << n << rn << m << endl; //776
rn = m ; Makes n equal to m (doesn't make rn refer to m)

cout << n << rn << m << endl; //666

96
const Reference
• A const reference will not let you change the
value it references:
• Example:
int n = 5;
const int & rn = n;

rn = 6; // error!!

• const reference is like a const pointer to a


const object.

97
References vs Pointers
Everything that is accomplished by references can be
accomplished by pointers but the syntax of references is
simpler:
Example
int n= 5;
int &rn = n;
int *const p = &n;
*p = 6;
rn = 6; Same effect
Pointer fun video: https://youtu.be/i49_SNt4yfk

98
Pointers and const
There are two different ways that pointers and
const can be intermixed:
1. Constant pointer
2. Pointer to a constant variable

99
Constant Pointer
• A const pointer must be initialized to a value
upon declaration, and its value can not be
changed.
• However, because the value being pointed to is
still non-const, it is possible to change the value
being pointed to via dereferencing the pointer:

int *const p = &i;


*p = 6; // it is O.K.
p = &j; // NOT O.K.
100
Pointer to a const variable
• It is also possible to declare a pointer to a constant
variable by using the const before the data type:
int i;
const int * p = &i;
*p = 6; // it is NOT O.K., because i is
//treated as constant when accessed by p.
• However, it can be changed independently:
i = 6; // It is O.K.
• It is also possible to declare a const pointer to a
constant value:
const int n = 5;
const int * const p = &n;
101
Parameter Passing
In C, all parameters are passed by value (call by value).
But C++ offers three options:
•Call by value
– Copy of data passed to function
– Changes to copy do not change original
•Call by reference
– Uses &
– Avoids a copy and allows changes to the original
•Call by constant reference
– Uses const&
– Avoids a copy and guarantees that actual parameter will not
be changed

102
Example
#include <iostream>
using std::cout;
using std::endl;

int squareByValue( int ); // pass by value


void squareByReference( int & ); // pass by reference
int squareByConstReference ( const int & ); // const ref.

int main()
{ int x = 2, z = 4, r1, r2;

r1 = squareByValue(x);
squareByReference( z );
r2 = squareByConstReference(x);

cout << "x = " << x << " z = “ << z << endl;
cout << “r1 = " << r1 << " r2 = " << r2 << endl;
return 0;
}
103
Example (cont.)
int squareByValue( int a )
{
return a *= a; // caller's argument not modified
}
void squareByReference( int &cRef )
{
cRef *= cRef; // caller's argument modified
}
int squareByConstReference (const int& a )
{
// a *= a; not allowed (compiler error)
return a * a;
}

104
Improving the Complex Class
#ifndef _Complex_H Old class:
#define _Complex_H

using namespace std;


class Complex
{
float re, im; // by default private
public:
Complex(float x = 0, float y = 0)
: re(x), im(y) { }

Complex operator*(const Complex& rhs) const;


float modulus() const;
void print() const;
};

#endif

105
Complex class Interface in the file Complex.h
Improving the Complex Class
#include <iostream>
#include <cmath>
#include "Complex.h"

Complex Complex::operator*(const Complex& rhs) const


{
Complex prod;
prod.re = (re*rhs.re - im*rhs.im);
prod.im = (re*rhs.im + im*rhs.re);
return prod;
}
float Complex::modulus() const
{
return sqrt(re*re + im*im);
}
void Complex::print() const
{
std::cout << "(" << re <<"," << im << ")" <<
std::endl;
}
106
Complex class implementation in file Complex.cpp
The uses of keyword const
We may encounter const in the following cases:
1. Const reference parameter:
Complex operator*(const Complex& rhs) const;
In this case it means the parameter cannot be modified.

2. Const member function:


Complex operator*(const Complex& rhs) const;

In this case it means the function cannot modify class members.

3. Const object/variable:
const Complex c1(3, 4);

In this case it means the object cannot be modified.


107
Memory Management
In C++ we use new and delete instead of malloc
and free used in C
– new - automatically creates object of proper size, calls
constructor, returns pointer of the correct type
– delete - destroys object (calls the destructor) and frees
space

• Example:
int* pi = new int(6);
Complex *pc = new Complex(3, 5);
delete pi;
delete pc;
108
// Allocate an array of complex objects (calls the
default constructor for each object).
Complex *ptr1 = new Complex [10];

for (int i = 0; i < 10; ++i)


ptr[i]->print();

delete[] ptr1; // note the delete[] syntax

// similar for int


int* ptr2 = new int[12];

// free up the dynamically allocated array


delete [] ptr2; //use [] iff [] is used in allocation

109
Default Arguments Revisited
• In C++ functions can have default arguments
• This is specified in the function declaration (not
the definition):
int foo(int x = 1, int y = 2, int z = 3);

foo(); // all parameters use the default value


foo(5); // y and z use the default value
foo(5,8); // z uses the default value
foo(5,8,9); // default values are not used

110
Default Arguments Revisited
• Note that it is impossible to suppy a user-defined value for z without also
supplying a value for x and y. That is the following does not work:

• For this reason the default parameters must be the rightmost ones:
foo(,,9); // compile error

int foo(int x = 1, int y = 2, int z); // WRONG


int foo(int z, int x = 1, int y = 2); // CORRECT

111
Function Overloading Revisited
• Functions with the same name and different parameters
• Overloaded functions should perform similar tasks
(otherwise it would be confusing):
• Function to square ints and function to square floats
int square( int x) {return x * x;}
float square(float x) { return x * x;}

• Compiler chooses based on the actual parameter types:

square(4); // calls the integer version


square(4.0f); // calls the float version

112
Function Overloading Revisited
• Functions that only differ by return type cannot be
overloaded:

int square(int x);


float square(int x); // Compile error

113
Operator Overloading Revisited
• Remember that we overloaded the * operator for the Complex
class.
• Operator overloading allows us to use existing operators for
user-defined classes.
• The following operators can be overloaded:

• Note that the precedence, associativity, and arity of the


operators cannot be changed!
114
Copy Constructor
 The copy constructor for a class is responsible for
creating copies of objects of that class type whenever
one is needed. This includes:
1. when the user explicitly requests a copy of an
object,
2. when an object is passed to function by value, or
3. when a function returns an object by value.

115
Example
//The following is a copy constructor
//for Complex class. Since it is same
//as the compiler’s default copy
//constructor for this class, it is
//actually redundant.

Complex::Complex(const Complex & C )


{
re = C.re;
im = C.im;
}

116
Example
class MyString
{
public:
MyString(const char* s = ””);
MyString(const MyString& s);
...
private:
int length;
char* str;
};

117
Example (cont.)
MyString::MyString(const MyString& s)
{
length = s.length;
str = new char[length + 1];
strcpy(str, s.str);
}

118
Calling the copy constructor
• Examples:
MyObject a; // default constructor call
MyObject b(a); // copy constructor call
MyObject bb = a; // identical to bb(a) : copy
//constructor call
MyObject c; // default constructor call
c = a; // assignment operator call

119
Assignment by Default:
Memberwise Copy
• Assignment operator (=)
– Sets variables equal, i.e., x = y;
– Can be used to assign an object to another
object of the same type
– Memberwise copy — member by member
copy
myObject1 = myObject2;
– This is shallow copy.

120
this Pointer
• Each class object has a pointer which
automatically points to itself. The pointer is
identified by the keyword this.
• Another way to think of this is that each member
function (but not friends) has an implicit first
parameter; that parameter is this, the pointer
to the object calling that function.

121
Example: overloading operator=
// defining an overloaded assignment operator
Complex & Complex :: operator=(const Complex & rhs )
{
// don't assign to yourself!
if ( this != &rhs ) // note the "address of" rhs
// why?
{
this -> Re = rhs.Re; // correct but
//redundant: means Re = rhs.Re
this -> Imag = rhs.Imag;
}
return *this; // return the calling class object
// enables cascading
}

122
Example
MyString& MyString::operator=(const MyString& rhs)
{
if (this != &rhs) {
delete[] this->str; // donate back useless
memory

this->length = rhs.length;

// allocate new memory


this->str = new char[this->length + 1];

strcpy(this->str, rhs.str); // copy characters


}
return *this; // return self-reference
}

123
Copy constructor and assignment operator
• Note that the copy constructor is called when a new object is being
created
• The assignment operator is called when an existing object is assigned
to a new object

class MyObject {
public:
MyObject(); // Default constructor
MyObject(const MyObject &a); // Copy constructor
MyObject& operator=(const MyObject& a) // Assignment op.
};
MyObject a; // constructor called
MyObject b = a; // copy constructor called
b = a; // assignment operator called
124
Destructor
• For classes with pointers we also need to define a
destructor to avoid memory leaks
class MyString {
public:
MyString(const char* s = ””);
MyString(const MyString& s);
~MyString(); // destructor
MyString& operator=(const MyString& s);
...
private:
int length;
char* str;
};

125
Destructor
• For classes with pointers we also need to define a
destructor to avoid memory leaks
MyString::~MyString()
{
delete[] str;
}

126
Rule of Three
• Whenever you need to define a copy constructor, assignment operator, or the destructor, you
must define all three of them
• This is known as the rule of three
• In general, for every class that contains pointer members you must define all three functions

127
static Class Members
• Shared by all objects of a class
– Normally, each object gets its own copy of each variable
• Efficient when a single copy of data is enough
– Only the static variable has to be updated
• May seem like global variables, but have class scope
– Only accessible to objects of same class
• Exist even if no instances (objects) of the class exist
• Can be variables or functions
• public, private, or protected

128
Example
In the interface file:
private:
static int count;
...
public:
static int getCount();
...

129
Implementation File
int Complex::count = 0;

int Complex::getCount()
{
return count;
}
Complex::Complex()
{
Re = 0;
Imag = 0;
count ++;
}

130
Driver Program
cout << Complex :: getCount() << endl;
Complex c1;
cout << c1.getCount();

131
Templates
• The template allows us to write routines
that work for arbitrary types without
having to know what these types will be.

• Two types:
– Function templates
– Class templates

132
Function Templates
• A function template is not an actual function;
instead it is a design (or pattern) for a function.
• The compiler creates the actual function based on
the actual types used in the program.
// swap function template.

template < class T>


void swap( T &lhs, T &rhs )
{
T tmp = lhs;
lhs = rhs;
rhs = tmp;
}

The swap function template


133
Using a template
• Instantiation of a template with a particular type, logically
creates a new function.
• Only one instantiation is created for each parameter-type
combination.
int main()
{ int x = 5, y = 7;
double a = 2, b = 4;
swap(x,y); //instanties an int version of swap
swap(x,y); //uses the same instantiation
swap(a,b); //instantiates a double version of swap

cout << x << “ “ << y << endl;


cout << a << “ “ << b << endl;

// swap(x, b); // Illegal: no match


return 0;
}
134
Class templates
• Class templates are used to define generic classes:
– e.g. it may be possible to use a class that defines several operations on a
collection of integers to manipulate a collection of real numbers.

template <class T>


class TemplateTest
{
// this class can use T as a generic type
public:
void f(T a);
T g();
...
private:
T x, y, z;
...
};

135
Implementation
• Each member function must be declared as a template.
• All member functions must be implemented in the header file
(so that the compiler can find their definition and replace “T”
with the actual parameter type)

// Typical member implementation.


template <class T>
void TemplateTest<T>::f(T a)
{
// Member body
}

136
Object declarations using
template classes

Form:
class-name <type> an-object;
Interpretation:
– Type may be any defined data type. Class-name
is the name of a template class. The object
an-object is created when the arguments
specified between < > replace their
corresponding parameters in the template class.

137
Example
// Memory cell interface (MemoryCell.h)

template <class T>


class MemoryCell
{
public:
MemoryCell(const T& initVal = T());
const T& read( ) const;
void write(const T& x);

private:
T storedValue;
};

138
Class template implementation
// Implementation of class members

template <class T>


MemoryCell<T>::MemoryCell(const T& initVal) :
storedValue(initVal){ }

template <class T>


const T& MemoryCell<T>::read() const
{
return storedValue;
}

template <class T>


void MemoryCell<T>::write(const T& x)
{
storedValue = x;
}
139
A simple test routine
int main()
{
MemoryCell<int> m; // instantiate int version
MemoryCell<float> f; // instantiate float ver.
MemoryCell<int> m2; // use the previously created
class

m.write(5);
m2.write(6);
f.write(3.5);
cout << “Cell content: ” << m.read() << endl;
cout << “Cell content: ” << m2.read() << endl;
cout << “Cell content: ” << f.read() << endl;
return 0;
}

140
Friend functions - revisited
• A friend function of a class is a nonmember
function of the class, but has access to all members of
the class.

• Reserved word friend appears only in the function


prototype(not in definition of the friend function)

141
Example 1: Complex Class
#include <iostream>
#ifndef _Complex_H
#define _Complex_H
using namespace std;
class Complex
{ private: // default
float Re, Imag;
public:
Complex( float x = 0, float y = 0 )
{ Re = x; Imag = y;}

~Complex() { }

float modulus();
void print() const;
friend void dummy(Complex One); //only main’s dummy has
//access
};
#endif Complex class Interface in the file Complex.h 142
Example: Friend functions of a Class (cont’d)

void dummy(Complex One){


One.Re = 3;
One.Imag = 5;
cout << One.Re << One.Imag << endl;
}

...

int main(){
Complex MyComplexNo(1,1);
dummy(MyComplexNo);
return 0;
}

143
Example 2: Complex Class
#include <iostream>
#ifndef _Complex_H
#define _Complex_H
using namespace std;
class Complex
{ private:
float Re, Imag;
public:
Complex( float x = 0, float y = 0 )
{ Re = x; Imag = y;}
~Complex() { }
Complex operator* ( Complex & rhs ) const;
float getReal() const;
float getImag() const;
float modulus() const;
friend ostream & operator<< (ostream &os, Complex & rhs);
};
#endif
Complex class Interface in the file Complex.h 144
Using the class in a Driver File
#include <iostream>
#include "Complex.h"
using namespace std;
int main()
{
Complex c1, c2(1), c3(1,2);
float x;

c1 = c2 * c3 * c2;

x = c1.modulus();

cout << c1 << " " << c2 << endl;


return 0;
}

A program that uses Complex in file TestComplex.cpp 145


Implementation of Complex Class
// File complex.cpp
#include <iostream>
#include “Complex.h"

Complex Complex:: operator*( Complex & rhs )


{
Complex prod; //some place to store the results...
prod.Re = (Re*rhs.Re - Imag*rhs.Imag);
prod.Imag = (Imag*rhs.Re + Re*rhs.Imag);
return prod;
}
float Complex:: modulus() const
{ // this is not the real def of complex modulus
return Re / Imag;
}
ostream & operator<< (ostream & out, Complex & rhs)
{ out << "(" << rhs.Re <<"," << rhs.Imag << ")";
return out; // allow for concat of << operators
}
float Complex::getReal() const { return Re; }
float Complex::getImag() const { return Imag; }

Complex class implementation in file Complex.cpp 146


Recap of friend-ship

147
C++ Error Handling
• In C, errors are reported by returning error codes from
functions:
int read(const char* filename, char data[])
{
FILE* fp = fopen(filename, “r”);
if (fp == NULL)
return -1; // indicate error

// read file contents into data


...
}

148
C++ Error Handling
• In C++, we have a more advanced mechanism called
exceptions
• It uses three keywords: throw, catch, try
• The function that encounters an error throws an exception:

int read(const char* filename, char data[])


{
FILE* fp = fopen(filename, “r”);
if (fp == NULL)
throw “file open error”; // indicate error

// read file contents into data


...
}

149
C++ Error Handling
• This exception must be caught, otherwise the program will
abnormally terminate:
int main()
{
char data[128];
try {
read(“test.txt”, data);
... // some other code
}
catch(const char* error) {
// if read throws an exception,
// program will continue executing from here
cout << “Error message:” << error << endl;
}
}
150
C++ Error Handling
• Note that we throw an object or a variable, and we catch an
object or a variable. These types should match for the
exception to be caught
• In the previous example we threw a const char* and
caught a const char*, so it was correct

151
Another Example
• We can also throw an object of a user defined class:

class FileReadError
{
};

int read(const char* filename, char data[])


{
FILE* fp = fopen(filename, “r”);
if (fp == NULL)
throw FileReadError(); // indicate error

// read file contents into data


...
}

152
C++ Error Handling
• Then we must update the catch code as well:

int main()
{
char data[128];
try {
read(“test.txt”, data);
}
catch(FileReadError error) {
// if read throws an exception,
// we will come here
}
}

153
C++ Error Handling
• There are many details of exception handling
• In this class, you should only know that the destructors of
the local objects will be called when an exception is thrown:

class A {
public:
~A() { cout << “destructor called” << endl; }
};

int read(const char* filename, char data[]) {


A a;
FILE* fp = fopen(filename, “r”);
if (fp == NULL)
throw “file open error”; // a's destructor will be called
}

154
Example of a try-catch Statement
 try
{
// Statements that process personnel data and may throw
// exceptions of type int, string, and SalaryError
}
catch ( int )
{
// Statements to handle an int exception
}
catch ( string s )
{
cout << s << endl; // Prints "Invalid customer age"
// More statements to handle an age error
}
catch ( SalaryError )
{
// Statements to handle a salary error
}
Standard Template Library
• I/O Facilities: iostream
• Garbage-collected String class
• Containers
– vector, list, queue, stack, map, set
• Numerical
– complex
• General algorithms
– search, sort
156
Using the vector
• Vector: Dynamically growing, shrinking array of elements
• To use it include library header file:
#include <vector>
• Vectors are declared as
vector<int> a(4); //a vector called a,
//containing four integers
vector<int> b(4, 3); //a vector of four
// elements, each initialized to 3.
vector<int> c; // 0 int objects
• The elements of an integer vector behave just like ordinary
integer variables
a[2] = 45;

157
Manipulating vectors
• The size() member function returns the
number of elements in the vector.
a.size() returns a value of 4.
• The = operator can be used to assign one
vector to another.
• e.g. v1 = v2, so long as they are vectors of
the same type.
• The push_back() member function allows
you to add elements to the end of a vector.
158
push_back() and pop_back()

vector<int> v;
v.push_back(3);
v.push_back(2);
// v[0] is 3, v[1] is 2, v.size() is 2
v.pop_back();
int t = v[v.size()-1]; //t=3
v.pop_back();

159

You might also like