0% found this document useful (0 votes)
18 views154 pages

CPP Lectures

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views154 pages

CPP Lectures

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 154

Computer Programming II – C++

Introduction to C++
C++ as a better C
• Created by Bjarne Stroustrup in 1979 to
bring Object-Oriented Programming
(OOP) support to C language.
• First “C with classes” compiler called
“Cfront” derived from C compiler called
“CPre”.
• “C++” name change in 1983 with new
features added like virtual functions,
function overloading, references with the
& symbol, the const keyword, and single-
line comments.
• Language updated again in 1989 to
include protected and static members, as
well as multiple inheritance.
• In 1998, the C++ standards committee
published the first international standard
for C++ known as “C++98” with STL.
• http://www.trytoprogram.com/cplusplu
s-programming/history/

2
Summary
Literal Constants
Integer & real number literals
Type Example
Octal 0123
Hexadecimal 0x5B1F
int 123
unsigned int 123u
long 123l
unsigned long 123ul
float 123.45f
double 123.45

5
Boolean, Character & string literals
A value of true representing true.
A value of false representing false.

Character literals are surrounded by single quotations 'x'.

String literals are surrounded by single quotations "Hello".

6
Flow Control
The if statement
if (condition) statement;
if (x == 100) cout << "x is 100";

if (x == 100)
cout << "x is 100";

if (x == 100) {
cout << "x is ";
cout << x;
}

if (x == 100) { cout << "x is "; cout << x;}

8
The if-else statement
if (condition) statement; else statement;

if (x == 100)
cout << "x is 100";
else
cout << "x is not 100";

if (x > 0)
cout << "x is positive";
else if (x < 0)
cout << "x is negative";
else
cout << "x is 0";

9
The ?: operator
Condition? expr-if-true : expr-if-false;
y = x > 100? 5 : 4;

int min(int a, int b) {


return a < b? a : b;
}

cout << (x == 100? "x is 100":"x is not 100");

10
The switch statement
switch (expression)
{
case constant1:
statements-group-1;
break;
case constant2:
statements-group-2;
break;
.
.
.
default:
default-statements-group;
}

11
The switch statement
switch (x) {
case 1:
cout << "x is 1";
break;
case 2:
cout << "x is 2";
break;
default:
cout << "value of x unknown";
}

switch (x) {
case 1:
case 2:
case 3:
cout << "x is 1, 2 or 3";
break;
default:
cout << "x is not 1, 2 nor 3";
}

12
The while statement
while (expression) statement;

int main () {
int n = 10;

while (n>0) {
cout << n << ", ";
--n;
}
cout << "liftoff!\n";
}

13
The do-while statement
do statement while (expression);

int main () {
string str;
do {
cout << "Enter text: ";
getline (cin, str);
cout << "You entered: " << str << '\n';
} while (str != "goodbye");
}

14
The for statement
for (initialization; condition; increase)
statement;
int main () {
for (int n=10; n>0; n--) {
cout << n << ", ";
}
cout << "liftoff!\n";
}

15
The for each statement (C++11)
for (declaration : range) statement;

int main () {
string str {"Hello!"};
for (char c : str)
{
cout << "[" << c << "]";
}
cout << '\n';
}

16
The goto statement (avoid!)
goto label;

label: statement;

LOOP:do {
if(a == 15) {
// skip the iteration.
a = a + 1;
goto LOOP;
}
cout << "value of a: " << a << endl;
a = a + 1;
} while(a < 20);

17
The continue statement
continue;

do {
if(a == 15) {
// skip the iteration.
a = a + 1;
continue;
}
cout << "value of a: " << a << endl;
a = a + 1;
}
while(a < 20)

18
The break statement
break;

do {
cout << "value of a: " << a << endl;
a = a + 1;
if(a > 15) {
// terminate the loop
break;
}
} while(a < 20);

19
C vs. C++
Casts
C C++
int i = 0; int i = 0;
long l = (long) i; long l = long(i);

21
Flexible Declarations
C C++
void makeit(void) void makeit(void)
{ {
int i; // 2000 lines of code
char *cp;
char *cp = new char[100];
/* imagine 2000 lines of code here */
for (int i = 0; i<100; ++i) {
/* allocate 100 bytes for cp */ /* do something */
/* 1st use of cp */ }
cp = malloc(100);
/* 1st use of i */ /* more code */
for (i = 0; i<100; ++i) { }
/* do something */
}

/* more code */
}

22
'struct' and 'union' Tags
C C++
struct foo { struct foo {
int a; int a;
float b; float b;
} }
struct foo f; foo f;

typedef struct {
int a;
float b;
} foo;
foo f;

23
The :: Operator
C C++
int a = 2; int a = 2;

int main() { int main() {


int a = 5; int a = 5;

cout << a << endl; cout << a << endl;


/* Cannot access cout << ::a << endl;
global variable (a) */ }
}
int x = 11;

void f4() {
int y = x; // global x
int x = 22;
y = x; // local x
}
24
'new' and 'delete'
C C++
void func(void) { void func() {
int *i; int *i = new int;

i = (int *) malloc(sizeof(int)); *i = 10;


*i = 10; cout << *i;
printf("%d", *i); delete i;
free(i); }
}

25
References
C C++
void swapint(int *a, int *b) { void swapint(int &a, int &b) {
int temp; int temp = a;
a = b;
temp = *a; b = temp;
*a = *b; }
*b = temp;
}

swapint(&i1, &i2); swapint(i1, i2);

26
Function Overloading
C C++
int abs(int i); int abs(int i);

long labs(long l); long abs(long l);


double dabs(double d); double abs(double d);

27
Type Inference - 'auto' keyword (C++11)
C C++
int main() int main()
{ {
int x = 4; auto x = 4;
double y = 3.37; auto y = 3.37;
int * ptr = &x; auto ptr = &x;
cout << sizeof(x) << endl cout << sizeof(x) << endl
<< sizeof(y) << endl << sizeof(y) << endl
<< sizeof(ptr) << endl; << sizeof(ptr) << endl;

return 0; return 0;
} }

28
Type Inference - 'decltype' keyword (C++11)
C C++

No equivalent

int fun1() { return 10; }


char fun2() { return 'g'; }

int main() {
// Data type of x is same as return type of fun1()
// and type of y is same as return type of fun2()
decltype(fun1()) x;
decltype(fun2()) y;

cout << typeid(x).name() << endl;


cout << typeid(y).name() << endl;

return 0;
}

29
Classes - Introduction
• The concept of classes, objects, member functions (methods),
and data members.
• Defining a class and creating an object.
• Defining methods (class’s behaviors).
• Declaring data members (class’s attributes).
• Calling methods of an object.
• Differences between data members and local variables of a
function.
• Constructors for initializing an object.
• Separating class’s interface from its implementation.

30
Class vs. Object
• A class is a template for objects
• Classes are the specifications describing objects
• Object holds the data and the actions defining the object
structure and behavior.

31
Class declaration & using
class Complex {
public:
double re;
double im;
};

int main()
{
Complex a;

a.re = 1;
a.im = 2;

cout << "(" << a.re << ", " << a.im << ")";
return 0;
}

32
Object methods (behaviours)
class Complex {
public:
void change(double x, double y) {
re = x; im = y;
}
void printOut() {
cout << "(" << re << ", " << im << ")";
} int main()
double re; {
double im; Complex a, b;
}; a.re = 1; a.im = 2;
b.change(a.re + 1, a.im - 3);

a.printOut();
b.printOut();
return 0;
}

33
Separating methods declaration from definition
class Complex {
public:
void change(double x, double y);
void printOut();
double re;
double im;
};

void Complex::change(double x, double y) {


re = x;
im = y;
}

void Complex::printOut() {
cout << "(" << re << ", " << im << ")";
}

34
Constructor
class Complex {
public:
Complex(double x, double y) {
re = x;
im = y;
}
void printOut() {
cout << "(" << re << ", " << im << ")";
}
double re; int main()
double im; {
}; Complex a(2,3), b = a;

a.printOut();
b.printOut();
return 0;
}

35
Separating class’s interface from its implementation

// main.cpp file
#include "Complex.h"

int main() {
Complex a(5, 6), b = a;

a.printOut();
b.printOut();
return 0;
}

36
Preprocessor wrappers
Separating class’s interface from its implementation
// Complex.h file // Complex.cpp file
#ifndef COMPLEX_H #include "Complex.h"
#define COMPLEX_H #include <iostream>

class Complex { using namespace std;


public:
Complex(double, double); Complex::Complex(double x, double y) {
void printOut(); re = x; im = y;
double re; }
double im;
}; void Complex::printOut() {
cout <<"("<<re<<", "<<im<<")";
#endif }

37
References (Aliases)

int main() {
int value = 5;
int * pointer = &value;
int & alias = value;

cout << value << endl;


cout << * pointer << endl;
cout << alias << endl;
return 0;
}

38
References as function parameters
void swapByValue(int, int); // does not work
void swapByPointer(int*, int*); void swapByValue(int x, int y)
void swapByAlias(int&, int&); {
int temp = x;
int main() { x = y;
int a = 5, b = 7; y = temp;
cout<<"a = "<<a<<", b = "<<b<<endl; }

swapByValue(a, b); void swapByPointer(int* x, int* y)


cout<<"a = "<<a<<", b = "<<b<<endl; {
int temp = *x;
swapByPointer(&a, &b); *x = *y;
cout<<"a = "<<a<<", b = "<<b<<endl; *y = temp;
}
swapByAlias(a, b);
cout<<"a = "<<a<<", b = "<<b<<endl; void swapByAlias(int& x, int& y)
{
return 0; int temp = x;
} x = y;
y = temp;
}
39
References as return value
int maximum(int x, int y) {
return x > y ? x : y;
}

int main() {
int a = 5, b = 7;
cout<<"a = "<<a<<", b = "<<b<<endl;

int c = maximum(a, b);


cout<<"c = "<<c<<endl;

cout<<"maximum(a, b) = "<<maximum(a, b)<<endl;

return 0;
}

40
References as return value
int& maximum(int& x, int& y) {
return x > y ? x : y;
}

int main() {
int a = 5, b = 7;
cout<<"a = "<<a<<", b = "<<b<<endl;

int c = maximum(a, b);


cout<<"c = "<<c<<endl;

cout<<"maximum(a, b) = "<<maximum(a, b)<<endl;

maximum(a, b) = 10;
cout<<"a = "<<a<<", b = "<<b<<endl;
return 0;
}

41
References as return value
int& maximum(int &x, int &y) {
return x > y ? x : y;
}

int main() {
int a = 5, b = 7;

cout<<"a= "<<a<<", b= "<<b<<endl;


cout<<"maximum(a, b)= "<<maximum(a, b)<<endl;

cout<<"&a="<<&a<<", &b="<<&b<<endl;
cout<<"&maximum(a, b)="<<&maximum(a, b)<<endl;
return 0;
}

42
References as return value
int vals[] = {1, 2, 3, 4, 5};

int& setValues(int i) {
return vals[i];
}

int main () {
cout << "Value before change" << endl;
for (int i = 0; i < 5; i++) {
cout << "vals[" << i << "] = " << vals[i] << endl;
}

setValues(1) = 10;
setValues(3) = 20;

cout << "Value after change" << endl;


for (int i = 0; i < 5; i++) {
cout << "vals[" << i << "] = " << vals[i] << endl;
}
return 0;
}
43
Types of constructors
• Default (zero arguments) constructor
• Parametrized constructor
• Copy constructor
• Move constructor (C++11)
• Conversion constructors (single argument)
class Complex {
• Explicit constructor public:
...
void printOut() {
cout<<"("<<re<<", "<<im<<")"<<endl;
}
private:
double re;
double im;
};

44
Default constructor
class Complex {
public:
// default constructor
Complex() {
re = 0; im = 0;
}
...
};

int main() {
Complex a;

a.printOut();

return 0;
}
45
Parametrized constructor
class Complex {
public:
// parametrized constructor
Complex(double x, double y) {
re = x; im = y;
}
...
};

int main() {
Complex a;
Complex b(1.5, 2.3);

a.printOut();
b.printOut();

return 0;
}
46
Copy constructor
class Complex {
public:
// copy constructor
Complex(Complex& x) {
re = x.re; im = x.im;
}
...
};

int main() {
Complex a;
Complex b(1.5, 2.3);
Complex c = b;

a.printOut();
b.printOut();
c.printOut();

return 0;
}
47
Conversion constructor (single argument)
class Complex {
public:
// conversion constructor
Complex(double x) {
re = x; im = 0;
}
...
};

int main() {
Complex a = 1.5;
Complex b;

b = 5.6;

a.printOut();
b.printOut();

return 0;
}
48
Explicit conversion constructor
class Complex {
public:
// conversion constructor
explicit Complex(double x) {
re = x; im = 0;
}
...
};

int main() {
Complex a = 1.5; // does not work
Complex b(1.5); // works

a = 5.6; // does not work


b = Complex(5.6); // works
a.printOut();
b.printOut();

return 0;
}
49
Initializing list
class Complex {
public:
// default constructor
Complex(): re(0), im(0) {}

// parametrized constructor
Complex(double x, double y): re(x), im(y) {}

// conversion constructor
Complex(double x): re(x), im(0) {}

// copy constructor
Complex(Complex& c): re(c.re), im(c.im) {}
...
};

50
Destructor
class Space { Space s1;
public:
Space(): sz(1) { void fn() {
ptr = new int[sz]; Space s4(4);
cout<<"Creating a Space("<<sz static Space s5(5);
<<") object"<<endl; }
}
Space(int s) : sz(s) { int main() {
ptr = new int[sz]; Space s2(2);
cout<<"Creating a Space("<<sz Space s3(3);
<<") object"<<endl; fn();
} {
~Space() { Space s6(6);
delete[] ptr; {
cout<<"Deleting a Space("<<sz fn();
<<") object"<<endl; Space s7(7);
} }
private: }
int * ptr; }
const int sz;
};
51
Constructors/Destructors calling order
Space s1; Creating a Space(1) object
Creating a Space(2) object
void fn() { Creating a Space(3) object
Space s4(4);
Creating a Space(4) object
static Space s5(5);
} Creating a Space(5) object
Deleting a Space(4) object
int main() { Creating a Space(6) object
Space s2(2); Creating a Space(4) object
Space s3(3); Deleting a Space(4) object
fn(); Creating a Space(7) object
{ Deleting a Space(7) object
Space s6(6);
Deleting a Space(6) object
{
fn(); Deleting a Space(3) object
Space s7(7); Deleting a Space(2) object
} Deleting a Space(5) object
} Deleting a Space(1) object
}

52
Setters & Getters
class Complex {
public:
// Constructors go here
void setRe(double x) { re = x; }
void setIm(double y) { im = y; }
double getRe() { return re; }
double getIm() { return im; }
private:
double re;
double im;
};

int main() {
Complex a(1, 2);
Complex b;
b.setRe(3); b.setIm(5);
cout << a.getRe() << ", " << a.getIm() << endl;
cout << b.getRe() << ", " << b.getIm() << endl;
}

53
Constant objects and constant methods
class Complex {
public:
// Constructors go here
void setRe(double x) { re = x; }
void setIm(double y) { im = y; }
double getRe() { return re; }
double getIm() { return im; }
private:
double re;
double im;
};

int main() {
const Complex a(1, 2);
Complex b;
b.setRe(3); b.setIm(5);
cout << a.getRe() << ", " << a.getIm() << endl; // Error
cout << b.getRe() << ", " << b.getIm() << endl;
}

54
Constant objects and constant methods
class Complex {
public:
// Constructors go here
void setRe(double x) { re = x; }
void setIm(double y) { im = y; }
double getRe() const { return re; }
double getIm() const { return im; }
private:
double re;
double im;
};

int main() {
const Complex a(1, 2);
Complex b;
b.setRe(3); b.setIm(5);
cout << a.getRe() << ", " << a.getIm() << endl; // Works fine now
cout << b.getRe() << ", " << b.getIm() << endl;
}

55
Hierarchical object composition
class Date {
public:
Date(): day(1), month(1), year(1970) { }
Date(int d, int m, int y): day(d), month(m), year(y) { }
void setDay(int d) { day = d; }
void setMonth(int m) { month = m; }
void setYear(int y) { year = y; }
int getDay() const { return day; }
int getMonth() const { return month; }
int getYear() const { return year; }
private:
int day, month, year;
};

class Person {
public:
Person(): name("name"), birthDate(Date()) { }
Person(string n, int d, int m, int y): name(n), birthDate(Date(d, m, y)) { }
Person(string n, Date d): name(n), birthDate(d) { }
string getName() const { return name; }
Date getBirthDate() const { return birthDate; }
private:
string name;
Date birthDate;
56
};
Hierarchical object composition
void printOut(const Date& d) {
cout << d.getDay() << "/"
<< d.getMonth() << "/"
<< d.getYear(); name: 1/1/1970
} Youssof: 22/10/2015
Firas: 4/10/2017
void printOut(const Person& p) {
cout << p.getName() << ": ";
printOut(p.getBirthDate());
}

int main() {
Person p1;
Person p2("Youssof", 22, 10, 2015);
Date bd(4,10,2017);
Person p3(“Firas", bd);
printOut(p1); cout << endl;
printOut(p2); cout << endl;
printOut(p3); cout << endl;
return 0;
}
57
Friend functions
class Date {
public:
Date(): day(1), month(1), year(1970) { }
Date(int d, int m, int y): day(d), month(m), year(y) { }
void setDay(int d) { day = d; }
void setMonth(int m) { month = m; }
void setYear(int y) { year = y; }
int getDay() const { return day; }
int getMonth() const { return month; }
int getYear() const { return year; }
friend void printOut(const Date& d);
private:
int day, month, year;
};

void printOut(const Date& d) {


cout << d.day << "/"
<< d.month << "/"
<< d.year;
}

58
Friend functions
class Person {
public:
Person(): name("name"), birthDate(Date()) { }
Person(string n, int d, int m, int y): name(n), birthDate(Date(d, m, y)) { }
Person(string n, Date d): name(n), birthDate(d) { }
string getName() const { return name; }
Date getBirthDate() const { return birthDate; }
friend void printOut(const Person& p);
private:
string name;
Date birthDate;
};

void printOut(const Person& p) {


cout << p.name << ": ";
printOut(p.birthDate);
}

59
Friend classes
class Date { class Person {
public: public:
... ...
friend class Display; friend class Display;
private: private:
... ...
}; };

class Display { int main() {


public: Person p1;
void printOut(const Date& d) { Person p2("Youssof", 22, 10, 2015);
cout << d.day << "/" Date bd(4,10,2017);
<< d.month << "/" Person p3("Firas", bd);
<< d.year; Display disp;
} disp.printOut(p1); cout << endl;
void printOut(const Person& p) { disp.printOut(p2); cout << endl;
cout << p.name << ": "; disp.printOut(p3); cout << endl;
printOut(p.birthDate); return 0;
} }
};

60
Friend class methods
class Date; void Display::printOut(const Date& d) {
class Person; cout << d.day << "/"
<< d.month << "/"
class Display { << d.year;
public: }
void printOut(const Date& d); void Display::printOut(const Person& p) {
void printOut(const Person& p); cout << p.name << ": ";
}; printOut(p.birthDate);
}
class Date {
public: int main() {
... Person p1;
friend void Display::printOut(const Date& d); Person p2("Youssof", 22, 10, 2015);
private: Date bd(4,10,2017);
... Person p3("Firas", bd);
}; Display disp;
disp.printOut(p1); cout << endl;
class Person { disp.printOut(p2); cout << endl;
public: disp.printOut(p3); cout << endl;
... return 0;
friend void Display::printOut(const Person& p); }
private:
...
};

61
Pointers to objects (new & delete operators)
class Complex {
private:
double re, im;
public:
Complex() { re = 0; im = 0; }
Complex(double x, double y) { re = x; im = y; }
void printOut() { cout<<"("<<re<<", "<<im<<")"<<endl; }
};
int main() {
Complex a, b(1,2);
Complex * p1 = new Complex;
Complex * p2 = new Complex(5,8);

a.printOut();
b.printOut();
(*p1).printOut();
p2->printOut();
delete p1;
delete p2;
return 0;
}
62
Object self-referencing (this keyword)
class Complex {
private:
double re, im;
public:
Complex() { re = 0; im = 0; }
Complex(double re, double im) { this->re = re; this->im = im; }
void printOut() { cout<<"("<<re<<", "<<im<<")"<<endl; }
};
int main() {
Complex a, b(1,2);
Complex * p1 = new Complex;
Complex * p2 = new Complex(5,8);

a.printOut();
b.printOut();
(*p1).printOut();
p2->printOut();
delete p1;
delete p2;
return 0;
}
63
Static data members
class Counter { int main() {
private: Counter a("a");
string name; cout<<"There is/are "
int count; <<a.getCount()
public: <<" Counter object(s) now"<<endl;
Counter(string n): name(n) { Counter b("b");
++count; cout<<"There is/are "
cout<<"Object "<<name <<b.getCount()
<<" is created"<<endl; <<" Counter object(s) now"<<endl;
} return 0;
~Counter() { }
--count;
cout<<"Object "<<name
<<" is deleted"<<endl;
}

int getCount() { return count; }


};

64
Static data members
class Counter { int main() {
private: Counter a("a");
string name; cout<<"There is/are "
static int count; <<a.getCount()
public: <<" Counter object(s) now"<<endl;
Counter(string n): name(n) { Counter b("b");
++count; cout<<"There is/are "
cout<<"Object "<<name <<b.getCount()
<<" is created"<<endl; <<" Counter object(s) now"<<endl;
} return 0;
~Counter() { }
--count;
cout<<"Object "<<name
<<" is deleted"<<endl;
}

int getCount() { return count; } Object a is created


}; There is/are 1 Counter object(s) now
Object b is created
int Counter::count = 0; There is/are 2 Counter object(s) now
Object b is deleted
Object a is deleted

65
Static methods
class Counter { int main() {
private: Counter a("a");
string name; cout<<"There is/are "
static int count; <<Counter::getCount()
public: <<" Counter object(s) now"<<endl;
Counter(string n): name(n) { Counter b("b");
++count; cout<<"There is/are "
cout<<"Object "<<name <<Counter::getCount()
<<" is created"<<endl; <<" Counter object(s) now"<<endl;
} return 0;
~Counter() { }
--count;
cout<<"Object "<<name
<<" is deleted"<<endl;
}

static int getCount() { return count; } Object a is created


}; There is/are 1 Counter object(s) now
Object b is created
int Counter::count = 0; There is/are 2 Counter object(s) now
Object b is deleted
Object a is deleted

66
Revision over functions
int maximum(int a, int b) { int maximum(int a, int b) {
if (a > b) return a > b? a : b;
return a; }
else
return b; int maximum(int a, int b, int c) {
} return a>b && a>c? a : (b > c? b : c);
}
int maximum(int a, int b, int c) {
if (a > b && a > c) int maximum(int a, int b, int c) {
return a; return a>maximum(b,c)? a:maximum(b,c);
else if (b > c) }
return b;
else int maximum(int a, int b, int c) {
return c; return maximum(a, maximum(b,c));
} }

67
Default argument values of functions
int sum(int a, int b) { int sum(int a, int b, int c=0, int d=0) {
return a + b; return a + b + c + d;
} }

int sum(int a, int b, int c) { int main() {


return a + b + c; int a = 3, b = 4, c = 5, d = 6;
}
cout << sum(a, b) << endl;
int sum(int a, int b, int c, int d) { cout << sum(a, b, c) << endl;
return a + b + c + d; cout << sum(a, b, c, d) << endl;
}
return 0;
int main() { }
int a = 3, b = 4, c = 5, d = 6;

cout << sum(a, b) << endl;


cout << sum(a, b, c) << endl; 7
cout << sum(a, b, c, d) << endl; 12
18
return 0;
}

68
Default arguments inside classes
class Complex {
private:
double re, im;
public:
Complex(double x = 0, double y = 0) : re(x), im(y) {}
...
};

class Complex {
private:
double re, im;
public:
Complex(double=0, double=0);
...
};

Complex::Complex(double x, double y) : re(x), im(y) {}

69
Some function overloading restrictions
• Function declarations that differ only in the return type are
equivalent.
char fn(int a);
void fn(int a);
• Member function declarations with the same name and the
name parameter-type-list cannot be overloaded if any of them
is a static member function declaration.
class Test {
public:
void fn(int a);
static void fn(int a);
};

70
Some function overloading restrictions (cont.)
• Parameter declarations that differ only in a pointer * versus an
array [] are equivalent.
void fn(char * str);
void fn(char str[]);
• Parameter declarations that differ only in the presence or
absence of const and/or volatile are equivalent.
void fn(int a);
void fn(const int a);
• Two parameter declarations that differ only in their default
arguments are equivalent.
void fn(int a = 1);
void fn(int a = 2);

71
Recursion
• Function calling itself
• Usage:
• Stop condition (special case)
• Test the special case first
• Recursive formula
• Calling the function with different input

72
Recursion (example 1)
// Calculating Factorial
long factorial(int n);

int main() {
cout << "5! = " << factorial(5);
return 0;
}
long factorial(int n) { long factorial(int n) {
long result = 1; if (n<=1)
for (int i = 1; i <= n; i++) { return 1;
result *= i; return n * factorial(n-1);
} }
return result;
}
Which one is better?

73
Recursion (example 2)
// Calculating Fibonacci series
int fib(int n);

int main() {
for (int i = 0; i < 10; i++)
cout << fib(i) << endl;
return 0;
}

int fib(int n) {
if (n <= 1)
return n;
return fib(n-1)+fib(n-2);
}

74
Recursion (example 3)
// Solving tower of Hanoi
void solve_toh(int nDisks, char start, char end, char middle);

int main() {
solve_toh(3, 'A', 'C', 'B'); // move 3 disks from A to C using B
return 0;
}

void solve_toh(int nDisks, char start, char end, char middle) {


if (nDisks > 0) {
solve_toh(nDisks - 1, start, middle, end);
cout << "Move one disk from " << start << " to " << end << endl;
solve_toh(nDisks - 1, middle, end, start);
}
}

75
Operators overloading
int main() {
string s1 = "Hello";
string s2 = "world!";
string s3 = s1 + ", " + s2;

cout << s1 << ", " << s2 << endl;


cout << s3 << endl;
return 0;
}

76
Operator overloading (member function)
class Complex {
private:
double re, im;
public:
Complex(double x=0, double y=0): re(x), im(y) {}

void print() const {


cout << "(" << re << ", " << im << ")";
}

Complex operator+(const Complex x) {


return Complex(re + x.re, im + x.im);
}
};
Complex Complex::operator+(const Complex x) {
int main() { return Complex(re + x.re, im + x.im);
Complex a(1, 4), b(5, -7); }
Complex c = a + b;

cout << "a: "; a.print(); cout << endl;


cout << "b: "; b.print(); cout << endl;
cout << "c: "; c.print(); cout << endl;
return 0;
}
77
Operator overloading (non-member function)
With friend functions:
class Complex {
private:
...
friend Complex operator+(const Complex c1, const Complex c2);
};

Complex operator+(const Complex c1, const Complex c2) {


return Complex(c1.re + c2.re, c1.im + c2.im);
}

With non-friend functions:


class Complex {
private:
...
// setters & getters
};

Complex operator+ (const Complex c1, const Complex c2) {


return Complex(c1.getRe() + c2.getRe(), c1.getIm() + c2.getIm());
}

78
Conversion function overloading
• Converts the object into another type class Complex {
private:
• Member method overloading only double re, im;
class Ratio { public:
private: Complex(double x = 0, double y = 0)
double x, y; : re(x), im(y) {}
public: Complex(const Complex& c)
Ratio(double a = 0, double b = 0) : re(c.re), im(c.im) {}
: x(a), y(b) {} void printOut() {
Ratio(const Ratio& c) cout<<"("<<re<<", "<<im<<")";
: x(c.x), y(c.y) {} }
void printOut() { operator double() {
cout << x << "/" << y; return sqrt(re * re + im * im);
} }
}; operator Ratio() {
return Ratio(re, im);
int main() { }
Complex c(3.4, 5.6); operator string() {
c.printOut(); cout << endl; stringstream ss;
double d = c; ss<<"("<<re<<", "<<im<<")";
cout << d << endl; return ss.str();
Ratio r = c; }
r.printOut(); cout << endl; };
return 0;
} 79
Pre-/Post-increment/decrement operators
class Store { int main() {
private: Store a(5);
int value; cout << a << endl;
public: cout << ++a << endl;
Store(int v = 0) : value(v) {} cout << a << endl;
Store(Store& s) : value(s.value) {} cout << a++ << endl;
cout << a << endl;
operator int() { }
return value;
}

// pre-increment operator
Store& operator++() {
value++;
return *this;
}

// post-increment operator
Store operator++(int) {
Store copy(*this);
++(*this); operator++();
return copy;
}
};
80
Operator overloading restrictions
• Almost any operator can be overloaded in C++. Except:
• member selector – (.)
• scope operator – (::)
• ternary operator – (? :)
• sizeof
• Only built-in operators can be overloaded. New operators can not be created.
• Arity (number of operands) of the operators cannot be changed.
• Precedence and associativity of the operators cannot be changed.
• Overloaded operators cannot have default arguments except the function call operator ()
which can have default arguments.
• Operators cannot be overloaded for built in types only. At least one operand must be used
defined type.
• Assignment (=), subscript ([]), function call (“()”), and member selection (->) operators
must be defined as member functions
• Except the operators specified in the last point, all other operators can be either member
functions or a non member functions.
• Some operators like (assignment)=, (address)& and comma (,) are by default overloaded.

81
C++ operator precedence
Precedence Operator Description Associativity
1 :: Scope resolution Left-to-right
2 a++ a-- Suffix/postfix increment and decrement
type() type{} Functional cast
a() Function call
a[] Subscript
. -> Member access
3 ++a --a Prefix increment and decrement Right-to-left
+a -a Unary plus and minus
! ~ Logical NOT and bitwise NOT
(type) C-style cast
*a Indirection (dereference)
&a Address-of
sizeof Size-of[note 1]
co_await await-expression (C++20)
new new[] Dynamic memory allocation
delete delete[] Dynamic memory deallocation
4 .* ->* Pointer-to-member Left-to-right
5 a*b a/b a%b Multiplication, division, and remainder
6 a+b a-b Addition and subtraction
82
C++ operator precedence
Precedence Operator Description Associativity
7 << >> Bitwise left shift and right shift Left-to-right
8 <=> Three-way comparison operator (since C++20)
9 < <= For relational operators < and ≤ respectively
> >= For relational operators > and ≥ respectively
10 == != For relational operators = and ≠ respectively
11 & Bitwise AND
12 ^ Bitwise XOR (exclusive or)
13 | Bitwise OR (inclusive or)
14 && Logical AND
15 || Logical OR
16 a?b:c Ternary conditional[note 2] Right-to-left
throw throw operator
co_yield yield-expression (C++20)
= Direct assignment (provided by default for C++ classes)
+= -= Compound assignment by sum and difference
*= /= %= Compound assignment by product, quotient, and remainder
<<= >>= Compound assignment by bitwise left shift and right shift
&= ^= |= Compound assignment by bitwise AND, XOR, and OR
17 , Comma Left-to-right
83
OOP concepts: Inheritance
class SuperClass {
public:
int superValue;
};

class SubClass : public SuperClass {


public:
int subValue;
};

int main() {
SubClass sub;

sub.subValue = 2;
sub.superValue = 5;

cout << sub.subValue << endl;


cout << sub.superValue << endl;
return 0;
}

84
Modes of Inheritance
class A {
public: class C : protected A {
int x; // x accessible as protected
protected: // y accessible as protected
int y; // z is not accessible from C
private: };
int z;
};
// 'private' is default for classes
class B : public A { class D : private A {
// x accessible as public // x accessible as private
// y accessible as protected // y accessible as private
// z is not accessible from B // z is not accessible from D
}; };
• Class B inheritance of class A is public (known globally)
• Class C inheritance of class A is protected (known to class, subclasses, and friends only)
• Class D inheritance of class A is private (known to class and friends only)

85
Constructor/Destructor calling order
class A {
public:
A() { cout << "A object created\n"; } A object created
~A() { cout << "A object deleted\n"; } A object created
};
B object created
class B : public A { A object created
public: B object created
B() { cout << "B object created\n"; }
C object created
~B() { cout << "B object deleted\n"; }
}; C object deleted
B object deleted
class C : public B { A object deleted
public:
C() { cout << "C object created\n"; }
B object deleted
~C() { cout << "C object deleted\n"; } A object deleted
}; A object deleted
int main() {
A x;
B y;
C z;
return 0;
}
86
Multiple inheritance

class Base {
...
};
class X : public Base { class X {
... ...
}; };
class Y : public Base { class Y {
... ...
}; };
class XY : public X, public Y { class XY : public X, public Y {
... ...
}; };

87
Multiple inheritance (example)
class Vehicle {
public:
Vehicle() {
cout << "This is a Vehicle\n";
}
};

class FourWheeler {
public:
FourWheeler() {
cout << "This is a 4-wheeler Vehicle\n";
}
};

class Car : public Vehicle, public FourWheeler {


};

int main() {
Car car;

return 0;
}

88
Constructor/Destructor calling order
(multiple-inheritance)
class A { A() constructor is called
public: B() constructor is called
A() { cout << "A() constructor is called\n"; }
A() constructor is called
A(int n) { cout << "A(int) constructor is called\n"; }
~A() { cout << "~A() destructor is called\n"; } C() constructor is called
}; D() constructor is called
class B : public A { A() constructor is called
public: B() constructor is called
B() { cout << "B() constructor is called\n"; } A() constructor is called
B(int n) { cout << "B(int) constructor is called\n"; }
C() constructor is called
~B() { cout << "~B() destructor is called\n"; }
}; D(int) constructor is called
class C : public A { ~D() destructor is called
public: ~C() destructor is called
C() { cout << "C() constructor is called\n"; } ~A() destructor is called
C(int n) { cout << "C(int) constructor is called\n"; } ~B() destructor is called
~C() { cout << "~C() destructor is called\n"; }
~A() destructor is called
};
class D : public B, public C { ~D() destructor is called
public: ~C() destructor is called
D() { cout << "D() constructor is called\n"; } ~A() destructor is called
D(int n) { cout << "D(int) constructor is called\n"; } ~B() destructor is called
~D() { cout << "~D() destructor is called\n"; } ~A() destructor is called
};
int main() {
D x;
D y(10);
return 0;
} 89
Constructor/Destructor calling order
(calling non-default constructor)
class A { A() constructor is called
public: B() constructor is called
A() { cout << "A() constructor is called\n"; }
A() constructor is called
A(int n) { cout << "A(int) constructor is called\n"; }
~A() { cout << "~A() destructor is called\n"; } C() constructor is called
}; D() constructor is called
class B : public A { A(int) constructor is called
public: B(int) constructor is called
B() { cout << "B() constructor is called\n"; } A(int) constructor is called
B(int n) : A(n) { cout << "B(int) constructor is called\n"; }
C(int) constructor is called
~B() { cout << "~B() destructor is called\n"; }
}; D(int) constructor is called
class C : public A { ~D() destructor is called
public: ~C() destructor is called
C() { cout << "C() constructor is called\n"; } ~A() destructor is called
C(int n) : A(n) { cout << "C(int) constructor is called\n"; } ~B() destructor is called
~C() { cout << "~C() destructor is called\n"; }
~A() destructor is called
};
class D : public B, public C { ~D() destructor is called
public: ~C() destructor is called
D() { cout << "D() constructor is called\n"; } ~A() destructor is called
D(int n) : B(n), C(n) { cout << "D(int) constructor is called\n"; } ~B() destructor is called
~D() { cout << "~D() destructor is called\n"; } ~A() destructor is called
};
int main() {
D x;
D y(10);
return 0;
} 90
Multiple inheritance
The diamond problem

91
Multiple inheritance
The diamond problem
#include <iostream> class TA : public Faculty, public Student {
using namespace std; public:
class Person { TA(int x)
public: : Student(x), Faculty(x) {
Person(int x) { cout << "TA::TA(int) called\n";
cout << "Person::Person(int) called\n"; }
} };
Person() {
cout << "Person::Person() called\n"; int main() {
} TA ta1(30);
}; }

class Faculty : public Person {


public:
Faculty(int x)
: Person(x) {
Person::Person(int) called
cout << "Faculty::Faculty(int) called\n"; Faculty::Faculty(int) called
} Person::Person(int) called
}; Student::Student(int) called
TA::TA(int) called
class Student : public Person {
public:
Student(int x)
: Person(x) {
cout << "Student::Student(int) called\n";
}
};
92
Virtual multiple inheritance
class Base { class Base {
... ...
}; };
class X : public Base { class X : public virtual Base {
... ...
}; };
class Y : public Base { class Y : public virtual Base {
... ...
}; };
class XY : public X, public Y { class XY : public X, public Y {
... ...
}; };

93
Multiple inheritance
The diamond problem
#include <iostream> class TA : public Faculty, public Student {
using namespace std; public:
class Person { TA(int x)
public: : Student(x), Faculty(x) {
Person(int x) { cout << "TA::TA(int) called\n";
cout << "Person::Person(int) called\n"; }
} };
Person() {
cout << "Person::Person() called\n"; int main() {
} TA ta1(30);
}; }

class Faculty : virtual public Person {


public:
Faculty(int x)
: Person(x) {
Person::Person() called
cout << "Faculty::Faculty(int) called\n"; Faculty::Faculty(int) called
} Student::Student(int) called
}; TA::TA(int) called

class Student : virtual public Person {


public:
Student(int x)
: Person(x) {
cout << "Student::Student(int) called\n";
}
};
94
Multiple inheritance
The diamond problem
#include <iostream> class TA : public Faculty, public Student {
using namespace std; public:
class Person { TA(int x)
public: : Student(x), Faculty(x), Person(x) {
Person(int x) { cout << "TA::TA(int) called\n";
cout << "Person::Person(int) called\n"; }
} };
Person() {
cout << "Person::Person() called\n"; int main() {
} TA ta1(30);
}; }

class Faculty : virtual public Person {


public:
Faculty(int x)
: Person(x) {
Person::Person(int) called
cout << "Faculty::Faculty(int) called\n"; Faculty::Faculty(int) called
} Student::Student(int) called
}; TA::TA(int) called

class Student : virtual public Person {


public:
Student(int x)
: Person(x) {
cout << "Student::Student(int) called\n";
}
};
95
Constructor/Destructor calling order
(virtual inheritance)
class A { A() constructor is called
public: B() constructor is called
A() { cout << "A() constructor is called\n"; }
C() constructor is called
A(int n) { cout << "A(int) constructor is called\n"; }
~A() { cout << "~A() destructor is called\n"; } D() constructor is called
}; A() constructor is called
class B : virtual public A { B() constructor is called
public: C() constructor is called
B() { cout << "B() constructor is called\n"; } D(int) constructor is called
B(int n) { cout << "B(int) constructor is called\n"; }
~D() destructor is called
~B() { cout << "~B() destructor is called\n"; }
}; ~C() destructor is called
class C : virtual public A { ~B() destructor is called
public: ~A() destructor is called
C() { cout << "C() constructor is called\n"; } ~D() destructor is called
C(int n) { cout << "C(int) constructor is called\n"; } ~C() destructor is called
~C() { cout << "~C() destructor is called\n"; }
~B() destructor is called
};
class D : public B, public C { ~A() destructor is called
public:
D() { cout << "D() constructor is called\n"; }
D(int n) { cout << "D(int) constructor is called\n"; }
~D() { cout << "~D() destructor is called\n"; }
};
int main() {
D x;
D y(10);
return 0;
} 96
Constructor/Destructor calling order
(virtual inheritance)
class A { A() constructor is called
public: B() constructor is called
A() { cout << "A() constructor is called\n"; }
C() constructor is called
A(int n) { cout << "A(int) constructor is called\n"; }
~A() { cout << "~A() destructor is called\n"; } D() constructor is called
}; A() constructor is called
class B : public virtual A { B(int) constructor is called
public: C(int) constructor is called
B() { cout << "B() constructor is called\n"; } D(int) constructor is called
B(int n) : A(n) { cout << "B(int) constructor is called\n"; }
~D() destructor is called
~B() { cout << "~B() destructor is called\n"; }
}; ~C() destructor is called
class C : public virtual A { ~B() destructor is called
public: ~A() destructor is called
C() { cout << "C() constructor is called\n"; } ~D() destructor is called
C(int n) : A(n) { cout << "C(int) constructor is called\n"; } ~C() destructor is called
~C() { cout << "~C() destructor is called\n"; }
~B() destructor is called
};
class D : public B, public C { ~A() destructor is called
public:
D() { cout << "D() constructor is called\n"; }
D(int n) : B(n), C(n) { cout << "D(int) constructor is called\n"; }
~D() { cout << "~D() destructor is called\n"; }
};
int main() {
D x;
D y(10);
return 0;
} 97
Constructor/Destructor calling order
(virtual inheritance)
class A { A() constructor is called
public: B() constructor is called
A() { cout << "A() constructor is called\n"; }
C() constructor is called
A(int n) { cout << "A(int) constructor is called\n"; }
~A() { cout << "~A() destructor is called\n"; } D() constructor is called
}; A(int) constructor is called
class B : public virtual A { B(int) constructor is called
public: C(int) constructor is called
B() { cout << "B() constructor is called\n"; } D(int) constructor is called
B(int n) : A(n) { cout << "B(int) constructor is called\n"; }
~D() destructor is called
~B() { cout << "~B() destructor is called\n"; }
}; ~C() destructor is called
class C : public virtual A { ~B() destructor is called
public: ~A() destructor is called
C() { cout << "C() constructor is called\n"; } ~D() destructor is called
C(int n) : A(n) { cout << "C(int) constructor is called\n"; } ~C() destructor is called
~C() { cout << "~C() destructor is called\n"; }
~B() destructor is called
};
class D : public B, public C { ~A() destructor is called
public:
D() { cout << "D() constructor is called\n"; }
D(int n) : A(n), B(n), C(n) { cout << "D(int) constructor is called\n"; }
~D() { cout << "~D() destructor is called\n"; }
};
int main() {
D x;
D y(10);
return 0;
} 98
Multiple inheritance
The ambiguity problem
class A {
public:
void doSomething() {...};
};

class B {
public:
void doSomething() {...};
};

class C : public A, public B {


public:
void start() {
// ambiguous call
doSomething();
}
};

99
Multiple inheritance
The ambiguity problem (solution)
class A {
public:
void doSomething() {...};
};

class B {
public:
void doSomething() {...};
};

class C : public A, public B {


public:
void start() {
// correct call
A::doSomething();
}
};

100
Multiple inheritance
The ambiguity problem
class A {
public:
void doSomething() {...};
};

class B { int main() {


public: C obj;
void doSomething() {...}; // ambiguous call
}; obj.doSomething();
return 0;
class C : public A, public B { }
public:
void start() {
// correct call
A::doSomething();
}
};

101
Multiple inheritance
The ambiguity problem (solution)
class A {
public:
void doSomething() {...};
};

class B { int main() {


public: C obj;
void doSomething() {...}; // correct call
}; obj.A::doSomething();
return 0;
class C : public A, public B { }
public:
void start() {
// correct call
A::doSomething();
}
};

102
Multiple inheritance
The ambiguity problem
#include <iostream> int main() {
using namespace std; D obj;

class A { obj.x = 5;
public:
int x;
}; cout << obj.x << "\n";

class B : public A {
return 0;
}; }

class C : public A {

};

class D : public B, public C {

};

103
Multiple inheritance
The ambiguity problem (solution)
#include <iostream> int main() {
using namespace std; D obj;

class A { obj.B::x = 5;
public: obj.C::x = 7;
int x;
}; cout << obj.B::x << "\n";
cout << obj.C::x << "\n";
class B : public A {
return 0;
}; }

class C : public A {

};

class D : public B, public C {

};

104
Multiple inheritance
The ambiguity problem (solution)
#include <iostream> int main() {
using namespace std; D obj;

class A { obj.B::x = 5;
public: obj.C::x = 7;
int x;
}; cout << obj.B::x << "\n";
cout << obj.C::x << "\n";
class B : public virtual A {
return 0;
}; }

class C : public virtual A {

};

class D : public B, public C {

};

105
Method overriding
class Shape {
protected:
string name;
public:
Shape(string n) : name(n) {
cout << "Shape " << name << " created" << endl;
}
string getName() const { return name; }
};

class Rect : public Shape {


public:
Rect(string n) : Shape(n) {
cout << "Rect " << name << " created" << endl;
}

};

int main() {
Shape sh("First");
Rect r("Second");

cout << "Shape: " << sh.getName() << endl;


cout << "Rect: " << r.getName() << endl;
return 0;
}

106
Method overriding
class Shape {
protected:
string name;
public:
Shape(string n) : name(n) {
cout << "Shape " << name << " created" << endl;
}
void printOut() const { cout << "Shape: "<< name << endl; }
};

class Rect : public Shape {


public:
Rect(string n) : Shape(n) {
cout << "Rect " << name << " created" << endl;
}
void printOut() const { cout << “Rect: "<< name << endl; }
};

int main() {
Shape sh("First");
Rect r("Second");

sh.printOut();
r.printOut();
return 0;
}

107
Polymorphism
class Shape {
protected:
...
};

class Rect : public Shape {


...
};

class Triangle : public Shape {


public:
Triangle(string n) : Shape(n) {
cout << "Triangle " << name << " created" << endl;
}
void printOut() const { cout << "Triangle: " << name << endl; }
};

class Circle : public Shape {


public:
Circle(string n) : Shape(n) {
cout << "Circle " << name << " created" << endl;
}
void printOut() const { cout << "Circle: " << name << endl; }
};

108
Polymorphism (early binding)
int main() { Shape s created
Shape s("s"); Shape r created
Rect r("r"); Rect r created
Triangle t("t"); Shape t created
Circle c("c"); Triangle t created
Shape *sh; Shape c created
sh = &s; sh->printOut(); Circle c created
sh = &r; sh->printOut(); Shape: s
sh = &t; sh->printOut(); Shape: r
sh = &c; sh->printOut(); Shape: t
Shape: c
return 0;
}

109
Polymorphism (late binding)
int main() { Shape s created
Shape s("s"); Shape r created
Rect r("r"); Rect r created
Triangle t("t"); Shape t created
Circle c("c"); Triangle t created
Shape *sh; Shape c created
sh = &s; sh->printOut(); Circle c created
sh = &r; sh->printOut(); Shape: s
sh = &t; sh->printOut(); Rect: r
sh = &c; sh->printOut(); Triangle: t
Circle: c
return 0;
}

class Shape {
...
virtual void printOut() const { cout << "Shape: " << name << endl; }
};

110
Polymorphism (using references)
int main() {
Shape s("s");
Rect r("r");
Triangle t("t");
Circle c("c");

Shape &shS = s;
shS.printOut();
Shape &shR = r;
shR.printOut();
Shape &shT = t;
shT.printOut();
Shape &shC = c;
shC.printOut();

return 0;
}

111
Rules for Virtual Functions
• Virtual functions cannot be static and cannot be a friend
function of another class.
• Virtual functions should be accessed using pointer or reference
of base class type to achieve run time polymorphism.
• The prototype of virtual functions should be same in base as
well as derived class.
• They are always defined in base class and overridden in
derived class. It is not mandatory for derived class to override
(or re-define the virtual function), in that case base class
version of function is used.
• A class may have virtual destructor, but it cannot have a virtual
constructor.

112
Abstract methods (pure virtual)
class Shape {
...
virtual void draw() = 0;
};
class Rect : public Shape {
...
virtual void draw() { cout << "Drawing Rect " << name << endl; };
};
class Triangle : public Shape {
...
virtual void draw() { cout << "Drawing Triangle " << name << endl; };
};
class Circle : public Shape {
...
virtual void draw() { cout << "Drawing Circle " << name << endl; };
};

int main() {
Rect r("r");
Triangle t("t");
Circle c("c");
Shape *sh;
sh = &r; sh->draw();
sh = &t; sh->draw();
sh = &c; sh->draw();
return 0;
}

113
Abstract vs. Concrete classes
• Any class containing abstract method is abstract
• Inherited abstract method should be implemented in the
subclass or else the subclass becomes abstract
• Abstract classes cannot be instantiated (cannot create objects
of it).
• Pointers to abstract class objects are possible. However, they
should point to concrete object of the class (instances of the
subclasses).

114
Virtual destructor
class Shape {
protected:
string name;

public:
Shape(string n="unknown") : name(n) {
cout << "Shape " << name << " created" << endl;
}
~Shape() {
cout << "Shape " << name << " destroyed" << endl;
}
virtual void printOut() const { cout << "Shape: " << name << endl; }
virtual void draw() = 0;
};

class Rect : public Shape {


public:
Rect(string n) : Shape(n) {
cout << "Rect " << name << " created" << endl;
}
~Rect() {
cout << "Rect " << name << " destroyed" << endl;
}
void printOut() const { cout << "Rect: " << name << endl; }
virtual void draw() { cout << "Drawing Rect " << name << endl; };
};

115
Virtual destructor
void printShape(Shape *s) { Shape r created
s->printOut(); Rect r created
} Shape t created
void drawShape(Shape *s) {
Triangle t created
s->draw(); Rect: r
} Drawing Rect r
Triangle: t
int main() { Drawing Triangle t
Rect r("r"); Triangle t destroyed
Triangle t("t"); Shape t destroyed
printShape(&r);
Rect r destroyed
drawShape(&r); Shape r destroyed
printShape(&t);
drawShape(&t);

return 0;
}

116
Virtual destructor
int main() { Shape r created
Shape *sh; Rect r created
sh = new Rect("r"); Rect: r
printShape(sh); Drawing Rect r
drawShape(sh); Shape r destroyed
delete sh; Shape t created
sh = new Triangle("t"); Triangle t created
printShape(sh); Triangle: t
drawShape(sh); Drawing Triangle t
delete sh; Shape t destroyed

return 0;
}

117
Virtual destructor
class Shape {
...
virtual ~Shape() {
cout << "Shape " << name << " destroyed" << endl;
}
...
}; Shape r created
Rect r created
int main() { Rect: r
Shape *sh; Drawing Rect r
sh = new Rect("r"); Rect r destroyed
printShape(sh); Shape r destroyed
drawShape(sh); Shape t created
delete sh; Triangle t created
sh = new Triangle("t"); Triangle: t
printShape(sh); Drawing Triangle t
drawShape(sh); Triangle t destroyed
delete sh; Shape t destroyed

return 0;
}
118
Anonymous object
int main() { Shape r created
Rect r("r"); Rect r created
Triangle *t = new Triangle("t"); Shape t created
Triangle *p = t; Triangle t created
Triangle t destroyed
delete t; Shape t destroyed
Rect r destroyed
return 0; Shape r destroyed
}

119
Anonymous class
class Button {
protected:
string label;
public:
Button(string l="unlabel") : label(l) {
cout << "Button " << label << " created" << endl;
}
virtual ~Button() {
cout << "Button " << label << " destroyed" << endl;
}
virtual void onClick() = 0;
};

int main() {
class : public Button {
public:
virtual void onClick() { cout << "Save button clicked" << endl; }
void setLabel(string l) { label = l; }
} saveBtn;
saveBtn.setLabel("Save");
saveBtn.onClick();
return 0;
}
120
The using keyword
• The using keyword is used to:
• Bring all members from the namespace into​ the current scope.
#include <iostream>
using namespace std;

int main() {

string s = "Hello World";


cout << s;
return 0;
}

121
The using keyword (cont.)
• The using keyword is used to:
• Bring a specific member from the namespace into the current scope.
#include <iostream>

int main() {
using std::cout;
using std::string;
string s = "Hello World";
cout << s;
return 0;
}

122
The using keyword (cont.)
• The using keyword is used to:
• Bring a base class method ​or variable into the current class’s scope.
class Base {
public:
void greet() {
cout << "Hello from Base" << endl;
}
};
class Derived : Base {
public:
using Base::greet;
void greet(string s) {
cout << "Hello from " << s << endl;
// Instead of recursing, the greet() method
// of the base class is called.
greet();
}
};
int main() {
Hello from Derived
Derived D;
Hello from Base
D.greet("Derived");
return 0;
} 123
The using keyword (cont.)
• The using keyword is used to:
• Bring a base class method ​or variable into the current class’s scope.
class Base {
public:
void sum(int a, int b) {
cout << "Sum: " << a + b << endl;
}
};
class Derived : protected Base {
public:
using Base::sum;
};
int main() {
Derived D;
// Due to protected inheritance, all the public methods
// of the base class become protected methods of the
// derived class. If the using keyword word was not used,
// calling sum like this would not have been possible.
D.sum(10, 20);
Sum: 30
return 0;
}

124
Templates
int maximum(int a, int b) {
return a > b? a : b;
}

double maximum(double a, double b) {


return a > b? a : b;
}

int sum(int a, int b, int c, int d) {


return a + b + c + d;
}

double sum(double a, double b, double c, double d) {


return a + b + c + d;
}

125
Function template
template <class T>
T maximum(T a, T b) {
return a > b? a : b;
}

template <typename T>


T sum(T a, T b, T c, T d) {
return a + b + c + d;
}

int main() {
cout << maximum(1, 4) << endl;
cout << maximum(1.2, 4.5) << endl;
// cout << maximum(5.3, 2) << endl; does not work
cout << maximum<double>(5.3, 2) << endl; // This works

cout << sum(1, 2, 3, 4) << endl;


cout << sum(1.2, 2.3, 3.4, 4.5) << endl;

return 0;
}
126
Function template specialization
template <class T>
void fun(T a) {
cout << "Main fun() template: " << a << endl;
}

template<>
void fun(double a) {
cout << "double fun() template: " << a << endl;
}
Main fun() template: 1
int main() Main fun() template: 3.14
{ Main fun() template: Hello
fun(1);
fun(3.14);
fun("Hello");
Main fun() template: 1
double fun() template: 3.14
return 0;
Main fun() template: Hello
}

127
Class templates
template <class T>
class Stack {
private:
T elems[10]; // elements

public:
void push(T const &); // push element
T pop(); // pop element
bool empty() const { // return true if empty.
...
} int main() {
}; Stack<int> intStack; // stack of ints
Stack<string> stringStack; // stack of strings
template <class T>
void Stack<T>::push(T const &elem) { // manipulate int stack
// append copy of passed element intStack.push(7);
} cout << intStack.pop() << endl;

template <class T> // manipulate string stack


T Stack<T>::pop() { stringStack.push("hello");
// remove last element cout << stringStack.pop() << endl;
} return 0;
}

128
Class templates specialization
template <class T>
class Stack {
private:
T elems[10]; // elements

public:
void push(T const &); // push element
T pop(); // pop element
bool empty() const { // return true if empty.
...
}
};

template <>
class Stack<string> {
...
};

129
Class templates with default type
template <class T = double>
class Stack {
private:
T elems[10]; // elements

public:
void push(T const &); // push element
T pop(); // pop element
bool empty() const { // return true if empty.
...
} int main() {
}; Stack<int> intStack; // stack of ints
Stack<> doubleStack; // stack of doubles

// manipulate int stack


intStack.push(7);
cout << intStack.pop() << endl;

// manipulate double stack


doubleStack.push(3.14);
cout << doubleStack.pop() << endl;
return 0;
}

130
Class templates with nontype parameters
template <class T, int sSize>
class Stack {
private:
T elems[sSize]; // elements

public:
void push(T const &); // push element
T pop(); // pop element
bool empty() const { // return true if empty.
...
} int main() {
}; Stack<int, 10> intStack;
Stack<string, 20> stringStack;
template <class T, int sSize>
void Stack<T,sSize>::push(T const &elem) { // manipulate int stack
// append copy of passed element intStack.push(7);
} cout << intStack.pop() << endl;

template <class T, int sSize> // manipulate string stack


T Stack<T,sSize>::pop() { stringStack.push("hello");
// remove last element cout << stringStack.pop() << endl;
} return 0;
}

131
Class templates with default type
template <class T = double> template <class T=double, int sSize=30>
class Stack { class Stack {
... ...
}; };

int main() { int main() {


// stack of ints // stack of 10 ints
Stack<int> intStack; Stack<int, 10> intStack;
// stack of doubles // stack of 30 strings
Stack<> doubleStack; Stack<string> stringStack;
... // stack of 30 doubles
return 0; Stack<> doubleStack;
} ...
return 0;
}

132
Overloading output/input streams
class Date {
private:
int day, month, year;
public:
Date(int d=11, int m=11, int y=1975);
void printOut();
friend ostream& operator<<(ostream& os, const Date& dt);
friend istream& operator>> (istream& is, Date& dt);
};

Date::Date(int d, int m, int y)


: day(d<1?1:d>31?31:d)
, month(m<1?1:m>12?12:m)
, year(y<0?-y:y) {}

void Date::printOut() { int main() {


cout << day << "/" << month << "/" << year; Date d1, d2(11, 12, 2019);
}
d1.printOut(); cout << endl;
ostream& operator<<(ostream& os, const Date& dt) { d2.printOut(); cout << endl;
os << dt.day << "/" << dt.month << "/" << dt.year;
return os; cin >> d2;
} cout << d1 << endl;
cout << d2 << endl;
istream& operator>> (istream& is, Date& dt) { return 0;
is >> dt.day >> dt.month >> dt.year; }
return is;
}
133
Sorting Algorithms
• Bubble sort void swap(int &x, int &y) {
int temp = x;
• Selection sort x = y;
y = temp;
• Insertion sort }

• Quick sort void printArray(int arr[], int size) {


for (int i = 0; i < size; i++)
cout << arr[i] << " ";
cout << endl;
• Merge Sort }
• Heap Sort ...

int main() {
• Radix Sort int arr[] = {64, 34, 25, 12, 22, 11, 90};
• Counting Sort int n = sizeof(arr) / sizeof(arr[0]);
printArray(arr, n);
• Bucket Sort
methodOfSort(arr, n);
• ShellSort
cout << "Sorted array: \n";
• … printArray(arr, n);

return 0;
} 134
Bubble Sort
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++)
for (int j = 0; j < n - i - 1; j++)
if (arr[j] > arr[j + 1])
swap(arr[j], arr[j + 1]);
}

int main() {
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr) / sizeof(arr[0]);
printArray(arr, n);

bubbleSort(arr, n);

cout << "Sorted array: \n";


printArray(arr, n);

return 0;
} 135
Selection Sort
void selectionSort(int arr[], int n) {
int min_idx;
for (int i = 0; i < n - 1; i++) {
min_idx = i;
for (int j = i + 1; j < n; j++)
if (arr[j] < arr[min_idx])
min_idx = j;
swap(arr[min_idx], arr[i]);
}
}

int main() {
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr) / sizeof(arr[0]);
printArray(arr, n);

selectionSort(arr, n);

cout << "Sorted array: \n";


printArray(arr, n);

return 0;
} 136
Insertion Sort
void insertionSort(int arr[], int n) {
int i, key, j;
for (i = 1; i < n; i++) {
key = arr[i];
j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
int main() {
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr) / sizeof(arr[0]);
printArray(arr, n);

insertionSort(arr, n);

cout << "Sorted array: \n";


printArray(arr, n);

return 0;
} 137
Quick Sort
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = (low - 1);
for (int j = low; j <= high - 1; j++) {
if (arr[j] <= pivot) {
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return (i + 1);
}

void quickSort(int arr[], int low, int high) {


if (low < high) { int main() {
int pi = partition(arr, low, high); int arr[] = {64, 34, 25, 12, 22, 11, 90};
quickSort(arr, low, pi - 1); int n = sizeof(arr) / sizeof(arr[0]);
quickSort(arr, pi + 1, high); printArray(arr, n);
}
} quickSort(arr, 0, n - 1);

cout << "Sorted array: \n";


printArray(arr, n);

return 0;
}

138
Standard Template Library (STL)
• A set of C++ template classes to provide common
programming data structures and functions such as lists,
stacks, arrays, etc.
• STL has four components:
• Containers
• Algorithms
• Functions (Functors)
• Iterators

139
STL Containers
• A container is a holder object that stores a collection of other objects (its
elements).
• The container manages the storage space for its elements and provides member
functions to access them, either directly or through iterators.
• Containers replicate structures very commonly used in programming: dynamic
arrays (vector), queues (queue), stacks (stack), heaps (priority_queue), linked
lists (list), trees (set), associative arrays (map)…
• Many containers have several member functions in common, and share
functionalities. The decision of which type of container to use for a specific need
does not generally depend only on the functionality offered by the container, but
also on the efficiency of some of its members (complexity).
• stack, queue and priority_queue are implemented as container adaptors.
Container adaptors are not full container classes, but classes that provide a
specific interface relying on an object of one of the container classes (such as
deque or list) to handle the elements. The underlying container is encapsulated
in such a way that its elements are accessed by the members of the container
adaptor independently of the underlying container class used.

140
STL Container class templates
• Sequence containers:
• array (C++11): Array class (class template)
• vector: Vector (class template)
• deque: Double ended queue (class template)
• forward_list (C++11): Forward list (class template)
• list: List (class template)
• Container adaptors:
• stack: LIFO stack (class template)
• queue: FIFO queue (class template)
• priority_queue: Priority queue (class template)

141
STL Container class templates
• Associative containers:
• set: Set (class template)
• multiset: Multiple-key set (class template)
• map: Map (class template)
• multimap: Multiple-key map (class template)
• Unordered associative containers:
• unordered_set (C++11): Unordered Set (class template)
• unordered_multiset (C++11): Unordered Multiset (class template)
• unordered_map (C++11): Unordered Map (class template)
• unordered_multimap (C++11): Unordered Multimap (class template)

142
STL Algorithms <algorithm>
• Non-modifying sequence operations:
• all_of : Test condition on all elements in range (function template)
• any_of : Test if any element in range fulfills condition (function
template)
• none_of : Test if no elements fulfill condition (function template)
• for_each: Apply function to range (function template)
• find: Find value in range (function template)
• find_if: Find element in range (function template)
• find_if_not: Find element in range (negative condition) (function
template)
• find_end: Find last subsequence in range (function template)
• find_first_of: Find element from set in range (function template)
• adjacent_find: Find equal adjacent elements in range (function
template)

143
STL Algorithms <algorithm>
• Non-modifying sequence operations:
• count: Count appearances of value in range (function template)
• count_if: Return number of elements in range satisfying condition
(function template)
• mismatch: Return first position where two ranges differ (function
template)
• equal: Test whether the elements in two ranges are equal (function
template)
• is_permutation: Test whether range is permutation of another (function
template)
• search: Search range for subsequence (function template)
• search_n: Search range for elements (function template)

144
STL Algorithms <algorithm>
• Modifying sequence operations:
• copy: Copy range of elements (function template)
• copy_n: Copy elements (function template)
• copy_if: Copy certain elements of range (function template)
• copy_backward: Copy range of elements backward (function template)
• move: Move range of elements (function template)
• move_backward: Move range of elements backward (function template)
• swap: Exchange values of two objects (function template)
• swap_ranges: Exchange values of two ranges (function template)
• iter_swap: Exchange values of objects pointed to by two iterators
(function template)
• transform: Transform range (function template)

145
STL Algorithms <algorithm>
• Modifying sequence operations:
• replace: Replace value in range (function template)
• replace_if: Replace values in range (function template)
• replace_copy: Copy range replacing value (function template)
• replace_copy_if: Copy range replacing value (function template)
• fill: Fill range with value (function template)
• fill_n: Fill sequence with value (function template)
• generate: Generate values for range with function (function template)
• generate_n: Generate values for sequence with function (function
template)
• remove: Remove value from range (function template)
• remove_if: Remove elements from range (function template)
• remove_copy: Copy range removing value (function template)
• remove_copy_if: Copy range removing values (function template)

146
STL Algorithms <algorithm>
• Modifying sequence operations:
• unique: Remove consecutive duplicates in range (function template)
• unique_copy: Copy range removing duplicates (function template)
• reverse: Reverse range (function template)
• reverse_copy: Copy range reversed (function template)
• rotate: Rotate left the elements in range (function template)
• rotate_copy: Copy range rotated left (function template)
• random_shuffle: Randomly rearrange elements in range (function
template)
• shuffle: Randomly rearrange elements in range using generator
(function template)

147
STL Algorithms <algorithm>
• Partitions:
• is_partitioned: Test whether range is partitioned (function template)
• partition: Partition range in two (function template)
• stable_partition: Partition range in two - stable ordering (function
template)
• partition_copy: Partition range into two (function template)
• partition_point: Get partition point (function template)

148
STL Algorithms <algorithm>
• Sorting:
• sort: Sort elements in range (function template)
• stable_sort: Sort elements preserving order of equivalents (function
template)
• partial_sort: Partially sort elements in range (function template)
• partial_sort_copy: Copy and partially sort range (function template)
• is_sorted: Check whether range is sorted (function template)
• is_sorted_until: Find first unsorted element in range (function template)
• nth_element: Sort element in range (function template)

149
STL Algorithms <algorithm>
• Sorting:
• sort: Sort elements in range (function template)
• stable_sort: Sort elements preserving order of equivalents (function
template)
• partial_sort: Partially sort elements in range (function template)
• partial_sort_copy: Copy and partially sort range (function template)
• is_sorted: Check whether range is sorted (function template)
• is_sorted_until: Find first unsorted element in range (function template)
• nth_element: Sort element in range (function template)

150
STL Algorithms <algorithm>
• Binary search (operating on partitioned/sorted ranges):
• lower_bound: Return iterator to lower bound (function template)
• upper_bound: Return iterator to upper bound (function template)
• equal_range: Get subrange of equal elements (function template)
• binary_search: Test if value exists in sorted sequence (function
template)

151
STL Algorithms <algorithm>
• Merge (operating on sorted ranges):
• merge: Merge sorted ranges (function template)
• inplace_merge: Merge consecutive sorted ranges (function template)
• includes: Test whether sorted range includes another sorted range
(function template)
• set_union: Union of two sorted ranges (function template)
• set_intersection: Intersection of two sorted ranges (function template)
• set_difference: Difference of two sorted ranges (function template)
• set_symmetric_difference: Symmetric difference of two sorted ranges
(function template)

152
STL Algorithms <algorithm>
• Heap:
• push_heap: Push element into heap range (function template)
• pop_heap: Pop element from heap range (function template)
• make_heap: Make heap from range (function template)
• sort_heap: Sort elements of heap (function template)
• is_heap: Test if range is heap (function template)
• is_heap_until: Find first element not in heap order (function template)

153
STL Algorithms <algorithm>
• Min/max:
• min: Return the smallest (function template)
• max: Return the largest (function template)
• minmax: Return smallest and largest elements (function template)
• min_element: Return smallest element in range (function template)
• max_element: Return largest element in range (function template)
• minmax_element: Return smallest and largest elements in range (function
template)
• Other:
• lexicographical_compare: Lexicographical less-than comparison (function
template)
• next_permutation: Transform range to next permutation (function
template)
• prev_permutation: Transform range to previous permutation (function
template)

154

You might also like