0% found this document useful (0 votes)
46 views149 pages

C++ Introduction: Giuseppe Andronico

C++ is an object-oriented programming language that is a superset of C. It was created by Bjarne Stroustrup and most recently updated in 2014. C++ supports procedural, object-oriented, and generic programming. It maintains C's efficiency while adding support for classes and object-oriented programming. Pointers store the address of another object in memory and are accessed via dereferencing. References are aliases for existing objects that cannot be reassigned. The auto keyword allows the compiler to deduce types in certain contexts. Basic I/O uses streams like cout and cin along with manipulators to control formatting. Classes define new user-defined types with representations and operations.

Uploaded by

Jenny Sni
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)
46 views149 pages

C++ Introduction: Giuseppe Andronico

C++ is an object-oriented programming language that is a superset of C. It was created by Bjarne Stroustrup and most recently updated in 2014. C++ supports procedural, object-oriented, and generic programming. It maintains C's efficiency while adding support for classes and object-oriented programming. Pointers store the address of another object in memory and are accessed via dereferencing. References are aliases for existing objects that cannot be reassigned. The auto keyword allows the compiler to deduce types in certain contexts. Basic I/O uses streams like cout and cin along with manipulators to control formatting. Classes define new user-defined types with representations and operations.

Uploaded by

Jenny Sni
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/ 149

C++ introduction

Giuseppe Andronico
Slides come from:

Lecture Slides for Programming in C++

By
Michael D. Adams
http://www.ece.uvic.ca/~mdadams/cppbook/
C++
created by Bjarne Stroustrup, Bell Labs
originally C with Classes, renamed as C++ in 1983
most recent specification of language in ISO/IEC 14882:2014 (informally
known as “C++14”)
procedural
loosely speaking is superset of C
directly supports object-oriented and generic programming
maintains efficiency of C
application domains: systems software, application software, device
drivers, embedded software, high-performance server and client
applications, entertainment software such as video games, native code for
Android applications
greatly influenced development of C# and Java

Copyright Oc 2015–2017 Michael D. Adams


Pointers
pointer is object whose value is address in memory where another object
is stored
pointer to object of type T denoted by T*
null pointer is special pointer value that does not refer to any valid
memory location
null pointer value provided by nullptr keyword
accessing object to which pointer refers called dereferencing
dereferencing pointer performed by indirection operator (i.e., “*”)
if p is pointer, *p is object to which pointer refers
if x is object of type T, &x is address of object (which has type T*)
example:

char c ;
char cp = nullptr;// cp is pointer to char
char* cp2 = &c; // cp2 is pointer to char
Pointer Example
code:
int i = 42;
int* p = &i;
assert(*p == 42);

assumptions (for some completely fictitious C++ language


implementation):
sizeof(int) is 4
sizeof(int*) is 4
&i is ((int*)1000)
&p is ((int*)1004)
memory layout:

Address Name

1000 42 i
1004 1000 p
References
reference is alias (i.e., nickname) for already existing object
two kinds of references:
1
lvalue reference
2
rvalue reference
lvalue reference to object of type T denoted by T& rvalue
reference to object of type T denoted by T&& initializing
reference called reference binding
lvalue and rvalue references differ in their binding properties (i.e., to what kinds
of objects reference can be bound)
in most contexts, lvalue references usually needed
rvalue references used in context of move constructors and move
assignment operators (to be discussed later)
example:
int x;
int& y = x; // y is lvalue reference to int
int&& tmp = 3; // tmp is rvalue reference to int
References Example
code:
int i = 42;
int& j = i;
assert(j == 42);

assumptions (for some completely fictitious C++ language


implementation):
sizeof(int) is 4
&i is ((int*)1000)
memory layout:

Address Name
1000 42 i, j
Addresses, Pointers, and References
References Versus Pointers
references and pointers similar in that both can be used to refer to some
other entity (e.g., object or function)
two key differences between references and pointers:
1 reference must refer to something, while pointer can have null value
(nullptr)
2 references cannot be rebound, while pointers can be changed to point to
different entity
references have cleaner syntax than pointers, since pointers must be
dereferenced upon each use (and dereference operations tend to clutter
code)
use of pointers often implies need for memory management (i.e., memory
allocation, deallocation, etc.), and memory management can introduce
numerous kinds of bugs when done incorrectly
often faced with decision of using pointer or reference in code
generally advisable to prefer use of references over use of pointers unless
compelling reason to do otherwise, such as:
must be able to handle case of referring to nothing
must be able to change entity being referred to
The auto Keyword
in various contexts, auto keyword can be used as place holder for type
in such contexts, implication is that compiler must deduce type
example:
auto i = 3; // i has type int
auto j = i; // j has type int
auto& k = i; // k has type int&
const auto& n = i; // n has type const int&
auto x = 3.14; // x has type double
very useful in generic programming (covered later) when types not always easy to
determine

can potentially save typing long type names can


lead to more readable code (if well used)
if overused, can lead to bugs (sometimes very subtle ones) and difficult to read
code
The for Statement: Example
example with single statement in loop body:
// Print the integers from 0 to 9 inclusive.
for (int i = 0; i < 10; ++i)
std::cout << i << ’\n’;
example with multiple statements in loop body:
int values[10];
// ...
int sum = 0;
for (int i = 0; i < 10; ++i) {
// Stop if value is negative.
if (values[i] < 0) {
break;
}
sum += values[i];
}
example with error in assumption about scoping rules:
for (int i = 0; i < 10; ++i) {
std::cout << i << ’\n’;
}
++i; // ERROR: i no longer exists
Range-Based for Statement

variant of for loop for iterating over elements in range


example:
int array[4] = {1, 2, 3, 4};
// Triple the value of each element in the array.
for (int& x : array) {
x *= 3;
}

range-based for loop nice in that it clearly expresses programmer intent


(i.e., iterate over each element of collection)
Basic I/O
relevant declarations and such in header file iostream
std::istream: stream from which characters/data can be read (i.e.,
input stream)
std::ostream: stream to which characters/data can be written (i.e.,
output stream)
std::istream std::cin standard input stream
std::ostream std::cout standard output stream
std::ostream std::cerr standard error stream
in most environments, above three streams refer to user’s terminal by
default
output operator (inserter) <<
input operator (extractor) >>
stream can be used as bool expression; converts to true if stream has
not encountered any errors and false otherwise (e.g., if invalid data
read or I/O error occurred)
Basic I/O Example
Basic I/O Example

1 #include <iostream>
2
3 int main() {
4 std::cout << "Enter an integer: ";
5 int x;
6 std::cin >> x;
7 if (std::cin) {
8 std::cout << "The integer entered was "
9 << x << ".\n";
10 } else {
11 std::cerr <<
12 "End-of-file reached or I/O error.\n";
13 }
14 }
I/O Manipulators
manipulators provide way to control formatting of data values written to
streams as well as parsing of data values read from streams
declarations related information for manipulators can be found in header
files: ios, iomanip, istream, and ostream
most manipulators used to control output formatting
focus here on manipulators as they pertain to output
manipulator may have immediate effect (e.g., endl), only affect next data
value output (e.g., setw), or affect all subsequent data values output (e.g.,
setprecision)
I/O Manipulators (Continued)
Name Description
setw set field width
setfill set fill character
endl insert newline and flush
flush flush stream
dec use decimal
hex use hexadecimal
oct use octal
showpos show positive sign
noshowpos do not show positive sign
left left align
right right align
fixed write floating-point values in fixed-point notation
scientific write floating-point values in scientific notation
setprecision for default notation, specify maximum number of mean-
ingful digits to display before and after decimal point; for
fixed and scientific notations, specify exactly how many
digits to display after decimal point (padding with trail- ing
zeros if necessary)
I/O Manipulators Example
1 #include <iostream >
2 #include <ios>
3 #include <iomanip >
4
5 int main() {
6 constexpr double pi = 3.1 415 92 653 5 ;
7 constexpr double big = 123456789.0 ;
8 // default notation
9 std::cout << pi << ’ ’ << big << ’\n ’;
10 // fixed-point notation
11 std::cout << std::fixed << pi << ’ ’ << big << ’\n ’;
12 // scientific notation
13 std::cout << std::scientific << pi << ’ ’ << big << ’\n ’;
14 // fixed-point notation with 7 digits after decimal point
15 std::cout << std::fixed << std::setprecision(7) << pi << ’ ’

16 << big << ’\n ’;


17 // fixed-point notation with precision and width specified
18 std::cout << std::setw(8) << std::fixed << std::setprecision(2)
19 << pi << ’ ’ << std::setw(20) << big << ’\n ’;
20 // fixed-point notation with precision, width, and fill specified
21 std::cout << std::setw(8) << std::setfill ( ’x ’) << std::fixed
22 << std::setpreci sion(2) << pi << ’ ’ << std::setw(20) << big << ’\n ’;
23 }
24
25 /* This program produces the following output:
26 3.14159 1.23457e+08
27 3.141593 123456789.000000
28 3.141593e+00 1.234568e+08
29 3.1415927 123456789.0000000
30 3.14 123456789.00
31 xxxx3.14 xxxxxxxx123456789.00
32 */
Classes
since fundamental types provided by language are quite limiting, language
provides mechanism for defining new (i.e., user-defined) types
class is user-defined type
class specifies:
1 how objects of class are represented
2 operations that can be performed on objects of class
not all parts of class are directly accessible to all code
interface is part of class that is directly accessible to its users
implementation is part of class that its users access only indirectly
through interface
Class Example
class typically has form:
class Widget // The class is named Widget.
{
public:
// public members
// (i.e., the interface to users)
// usually functions and types (but not data)
private:
// private members
// (i.e., the implementation details only
// accessible by members of class)
// usually functions, types, and data
};
Class Members
class consists of zero or more members
three basic kinds of members (excluding enumerators):
1
data member
2
function member
3
type member
data members define representation of class object
function members (also called member functions) provide operations on
such objects
type members specify any types associated with class
Access Specifiers
can control level of access that users of class have to its members
three levels of access:
1
public
2
protected
3
private
public: member can be accessed by any code
private: member can only be accessed by other members of class and
friends of class (to be discussed shortly)
protected: relates to inheritance (discussion deferred until later)
public members constitute class interface
private members constitute class implementation
Default Member Access
class members are private by default
two code examples below are exactly equivalent:
class Widget {
// ...
};

class Widget {
private:
// ...
};
The struct Keyword
struct is class where members public by default
two code examples below are exactly equivalent:

struct Widget {
// ...
};

class Widget {
public:
// ...
};
Data Members
class example:
class Vector_2 { // Two-dimensional vector class.
public:
double x ; // The x component of the vector.
}; double y ; // The y component of the vector.
void func() {
Vector_2 v;
v .x = 1.0; // Set data member x to 1.0
} v .y = 2.0; // Set data member y to 2.0

above class has data members x and y


members accessed by member-selection operator (i.e., “.”)
Function Members
class example:
class Vector_2 { // Two-dimensional vector class.
public:
void initialize(double newX, double newY);
double x; // The x component of the vector.
double y; // The y component of the vector.
};
void Vector_2::initialize(double newX, double newY) {
x = newX; // "x" means "this->x"
y = newY; // "y" means "this->y"
}
void func() {
Vector_2 v; // Create Vector_2 called v.
v.initialize(1.0, 2.0); // Initialize v to (1.0, 2.0).
}
above class has member function initialize
to refer to member of class outside of class body must use
scope-resolution operator (i.e., ::)
for example, in case of initialize function, we use
Vector_2::initialize
member function always has implicit parameter referring to class object
The this Keyword
member function always has implicit parameter referring to class object
implicit parameter accessible inside member function via this keyword
this is pointer to object for which member function is being invoked
data members can be accessed through this pointer
since data members can also be referred to directly by their names,
explicit use of this often not needed and normally avoided
example:
class Widget {
public:
int updateValue(int newValue) {
int oldValue = value; // "value" means "this->value"
value = newValue; // "value" means "this->value"
return oldValue;
}
private:
int value;
};
void func() {
Widget x;
x.updateValue(5);
// in Widget::updateValue, variable this equals &x
}
const Member Functions
member function has reference to object of class as implicit parameter
(i.e., object pointed to by this)
need way to indicate if member function can change value of object
const member function cannot change value of object
1 class Counter {
2 public:
3 int getCount() const
4 {return count;} // count means this->count
5 void setCount(int newCount)
6 {count = newCount;} // count means this->count
7 void incrementCount ()
8 {++count;} // count means this->count
9 private:
10 int count ; // counter value
11 };
12
13 void func(){
14 Counter ctr ;
15 ctr .setCount(0);
16 int count = ctr.getCount();
17 const Counter& ctr2 = ctr;
18 count = ctr2.getCount(); // getCount better be const!
19 }
Definition of Function Members in Class Body
member function whose definition is provided in body of class is
automatically inline
two code examples below are exactly equivalent:
class MyInteger {
public:
// Set the value of the integer and return the old value.
int setValue(int newValue) {
int oldValue = value;
value = newValue;
return oldValue;
}
private:
int value;
};

class MyInteger {
public:
// Set the value of the integer and return the old value.
int setValue(int newValue);
private:
int value;
};
inline int MyInteger::setValue(int newValue) {
int oldValue = value;
value = newValue;
return oldValue;
}
Type Members
example:
class Point_2 { // Two-dimensional point class.
public:
typedef double Coordinate; // Coordinate type.
Coordinate x; // The x coordinate of the point.
Coordinate y; // The y coordinate of the point.
};
void func() {
Point_2 p;
// ...
Point_2::Coordinate x = p.x;
// Point_2::Coordinate same as double
}

above class has type member Coordinate


to refer to type member outside of class body, we must use
scope-resolution operator (i.e., ::)
Class Example
1 class Widget {
2 public:
3 int setValue(int newValue) { // member function
4 int oldValue = value; // save old value
5 value = newValue; // change value to new value
6 return oldValue; // return old value
7 }
8 private:
9 friend void wasteTime();
10 void doNothing() {}
11 int value; // data member
12 };
13
14 void wasteTime() {
15 Widget x;
16 x.doNothing(); // OK: friend
17 x.value = 5; // OK: friend
18 }
19
20 void func(){
21 Widget x ; // x is object of type Widget
22 x.setValue(5); // call Widget’s setValue member
23 // sets x.value to 5
24 x.value = 5; // ERROR: value is private
25 x.doNothing(); // ERROR: doNothing is private
26 }
Constructors
when new object created usually desirable to immediately initialize it to
some known state
prevents object from accidentally being used before it is initialized
constructor is member function that is called automatically when object
created in order to initialize its value
constructor has same name as class (i.e., constructor for class T is
function T::T)
constructor has no return type (not even void)
constructor cannot be called directly (although placement new provides
mechanism for achieving similar effect, in rare cases when needed)
constructor can be overloaded
before constructor body is entered, all data members of class type are first
constructed
in certain circumstances, constructors may be automatically provided
sometimes, automatically provided constructors will not have correct
behavior
Default Constructor
constructor that can be called with no arguments known as default
constructor
if no constructors specified, default constructor automatically provided
that calls default constructor for each data member of class type (does
nothing for data member of built-in type)

class Vector { // Two-dimensional vector class.


public:
Vector() // Default constructor.
{x_ = 0.0; y_ = 0.0;}
// ...
private:
double x_ ; // The x component of the vector.
}; double y_ ; // The y component of the vector.
Vector v; // calls Vector::Vector(); v set to (0,0)
Vector x(); // declares function x that returns Vector
Copy Constructor
for class T, constructor taking lvalue reference to T as first parameter that
can be called with one argument known as copy constructor
used to create object by copying from already-existing object
copy constructor for class T typically is of form T(const T&)
if no copy constructor specified (and no move constructor or move
assignment operator specified), copy constructor is automatically
provided that copies each data member (using copy constructor for class
and bitwise copy for built-in type)
class Vector { // Two-dimensional vector class.
public:
Vector() {x_ = 0.0; y_ = 0.0;} // Default constructor
Vector(const Vector& v) // Copy constructor.
{x_ = v.x_; y_ = v.y_;}
// ...
private:
double x_ ; // The x component of the vector.
}; double y_ ; // The y component of the vector.
Vector v;
Vector w(v); // calls Vector::Vector(const Vector&)
Vector u = v; // calls Vector::Vector(const Vector&)
Move Constructor
for class T, constructor taking rvalue reference to T as first parameter that
can be called with one argument known as move constructor
used to create object by moving from already-existing object
move constructor for class T typically is of form T(T&&)
if no move constructor specified (and no destructor, copy constructor, or
copy/move assignment operator specified), move constructor is
automatically provided that moves each data member (using move for
class and bitwise copy for built-in type)
class Vector { // Two-dimensional vector class.
public:
// ...
Vector(Vector&& v) // Move constructor.
{x_ = v.x_; y_ = v.y_;}
// ...
private:
double x_; // The x component of the vector.
double y_; // The y component of the vector.
};
Vector f(); // declares function f that returns Vector
Vector v = f();
// calls Vector::Vector(Vector&&) if move not elided
Constructor Example
class Vector { // Two-dimensional vector class.
public:
Vector() // Default constructor.
{x_ = 0.0; y_ = 0.0;}
Vector(const Vector& v)
{x_ = v.x_; y_ = v.y_;}// Copy constructor.
Vector(Vector&& v) // Move
{x_ = v.x_; y_ = v.y_;} constructor.
Vector(double x, double y)
{x_ = x; y_ = y;} // Another constructor.
// ...
private:
double x_ ; // The x component of the vector.
}; double y_ ; // The y component of the vector.
Vector u; // calls Vector::Vector(); u set to (0,0)
Vector v(1.0, 2.0); // calls Vector::Vector(double, double)
Vector w(v); // calls Vector::Vector(const Vector&)
Vector z = u; // calls Vector::Vector(const Vector&)
Vector f(); // declares function f that returns Vector
Vector y = f();
// calls Vector::Vector(Vector&&) if move not elided

four constructors provided


Constructor Example 2
class VectorStore { // Set of vectors
public:
VectorStore() // Default constructor.
{v_ = nullptr;}
VectorStore(Vector& v) // Store vector
{v_ = &v;}

private:
Vector* v_
};
Initializer Lists
in constructor of class, often we want to control which constructor is used to
initialize each data member
since all data members are constructed before body of constructor is
entered, this cannot be controlled inside body of constructor
to allow control over which constructors are used to initialize individual data
members, mechanism called initializer lists provided
initializer list forces specific constructors to be used to initialize individual data
members before body of constructor is entered
data members always initialized in order of declaration, regardless of order in
initializer list
Initializer List Example
class ArrayDouble { // array of doubles class
public:
ArrayDouble(); // create empty array
ArrayDouble(int size); // create array of specified size
// ...
private:
// ...
};
class Vector { // n-dimensional real vector class
public:
Vector(int size) : data_(size) {}
// force data_ to be constructed with
// ArrayDouble::ArrayDouble(int)
// ...
private:
ArrayDouble data_; // elements of vector
};
Destructors
when object reaches end of lifetime, typically some cleanup required
before object passes out of existence
destructor is member function that is automatically called when object
reaches end of lifetime in order to perform any necessary cleanup
often object may have allocated resources associated with it (e.g.,
memory, files, devices, network connections, processes/threads)
when object destroyed, must ensure that any resources associated with
object are released
destructors often serve to release resources associated with object
destructor for class T always has name T::~T̃
destructor has no return type (not even void)
destructor cannot be overloaded
destructor always takes no parameters
if no destructor is specified, destructor automatically provided that calls
destructor for each data member of class type
sometimes, automatically provided destructor will not have correct
behavior
Destructor Example
example:
class Widget {
public:
Widget(int bufferSize) { // Constructor.
// allocate some memory for buffer
bufferPtr_ = new char[bufferSize];
}
~Widget() { // Destructor.
// free memory previously allocated
delete [] bufferPtr_;
}
// copy constructor, assignment operator, ...
private:
char* bufferPtr_; // pointer to start of buffer
};

without explicitly-provided destructor (i.e., with destructor automatically


provided by compiler), memory associated with bufferPtr_ would not be
freed
Motivation for Function Templates
consider following functions:
int max(int x, int y)
{return x > y ? x : y;}
double max(double x, double y)
{return x > y ? x : y;}

// more similar-looking max functions...

each of above functions has same general form ; that is, for some type T,
we have:
T max(T x, T y)
{return x > y ? x : y;}

would be nice if we did not have to repeatedly type, debug, test, and
maintain nearly identical code
in effect, would like code to be parameterized on type T
Function Templates
function template is family of functions parameterized by one or
parameters
each template parameter can be: non-type (e.g., integral constant), type,
template, or parameter pack (in case of variadic template)
syntax for template function has general form:
template <parameter list> function declaration
parameter list: parameters on which template function depends
function declaration: function declaration or definition
type parameter designated by class or typename keyword
template parameter designated by template keyword
template template parameter must use class keyword
non-type parameter designed by its type (e.g., bool, int)
example:
// declaration of function template
template <class T> T max(T x, T y);
// definition of function template
template <class T> T max(T x, T y)
{return x > y ? x : y;}
Function Templates (Continued)
to explicitly identify particular instance of template, use syntax:
function<parameters>
example:
for function template declaration:
template <class T> T max(T x, T y);
max<int> refers to int max(int, int)
max<double> refers to double max(double, double)
compiler only creates code for function template when it is instantiated
(i.e., used)
therefore, definition of function template must be visible in place where it
is instantiated
consequently, function template definitions usually appear in header file
template code only needs to pass basic syntax checks, unless actually
instantiated
Function Template Examples
1 // compute minimum of two values
2 template <class T>
3 T min(T x, T y) {
4 return x < y ? x : y;
5 }
6
7 // compute square of value
8 template <typename T>
9 T sqr(T x) {
10 return x * x;
11 }
12
13 // swap two values
14 template <class T>
15 void swap(T& x, T& y) {
16 T tmp = x;
17 x = y;
18 y = tmp;
19 }
20
21 // invoke function/functor multiple times
22 template <int N = 1, typename F, typename T>
23 void invoke(F func, const T& value) {
24 for (int i = 0; i < N; ++i) {
25 func(value);
26 }
27 }
Template Function Overload Resolution
overload resolution proceeds (in order) as follows:
1 look for an exact match with zero or more trivial conversions on
(nontemplate) functions; if found call it
2 look for function template from which function that can be called with exact
match with zero or more trivial conversions can be generated; if found, call it
3 try ordinary overload resolution for functions; if function found, call it;
otherwise, call is error

in each step, if more than one match found, call is ambiguous and is error
template function only used in case of exact match, unless explicitly forced
example:
template <class T>
T max(T x, T y) {return x > y ? x : y;}
void func(int i, int j, double x, double y) {
double z = max(x, y); // calls max<double>
int k = max(i, j); // calls max<int>
z = max(i, x); // ERROR: no match
z = max<double>(i, x); // calls max<double>
}
Qualified Names

qualified name is name that specifies scope


example:
#include <iostream>
int main(int argc, char** argv) {
for (int i = 0; i < 10; ++i) {
std::cout << "Hello, world!" << std::endl;
}
}

in above example, names std::cout and std::endl are qualified, while


names main, argc, argv, and i, are not qualified
Dependent Names

dependent name is name that depends on template parameter


example:
template <class T >
void func (const T & x ){
int i = T::magicValue;
// ...
}

name T::magicValue is dependent


Qualified Dependent Names
to avoid any potential ambiguities, compiler will automatically assume
qualified dependent name does not name type unless typename
keyword is used
must precede qualified dependent name that names type by typename
in following example, note use of typename keyword:
1 #include <vector>
2
3 template <class T>
4 void func(const T& x) {
5 std::vector <T> v(42, x);
6 // std::vector<T>::const_iterator is
7 // qualified dependent name
8 for (typename std::vector<T>::const_iterator i =
9 v.begin(); i != v.end(); ++i) {
10 // std::vector<T>::value_type is
11 // qualified dependent name
12 typename std::vector <T>::value_type x = *i;
13 // ...
14 }
15 // ...
16 }
1
Why typename is Needed
int x = 42;
2
3 template <class T> void func() {
4 // The compiler must be able to check syntactic
5 // correctness of this template code without
6 // knowing T. Without knowing T, however, the
7 // meaning of following line of code is ambiguous.
8 // Is it a declaration of a variable x or an
9 // expression consisting of a binary operator*
10 // with operands T::foo and x?
11
T::foo* x; // Does T::foo name a type or an object?
12 // ...
13 }
14
15 struct ContainsType {
16
using foo = int; // foo is type
17 // ...
18 };
19
20 struct ContainsValue {
21 static int foo; // foo is value
22 // ...
23 };
24
25 int main() {
26
// Only one of the following lines should be valid.
27 func<ContainsValue >();
28 func<ContainsType >();
29 }
Example: What is wrong with this code?
1
Example: What is wrong with this code?
// templates_1_0.cpp
2
3 #include <iostream >
4 #include <complex>
5 #include "templates_1_1.hpp"
6
7 int main() {
8 std::complex <double> a(0.0, 1.0);
9 auto b = square(a);
10 std::cout << b << ’\n’;
11 }

1 // templates_1_1.hpp
2
3
template <class T>
4
T square(const T&);

1 // templates_1_1.cpp
2
3 #include "templates_1_1.hpp"
4
5 template <class T>
6 T square(const T& x) {
7 return x * x; 257
8 }
Motivation for Class Templates
consider almost identical complex number classes:
1 class ComplexDouble {
2 public:
3 ComplexDouble(double x = 0.0, double y = 0.0) : x_(x), y_(y) {}
4 double real() const { return x_; }
5 double imag() const { return y_; }
6 // ...
7 private:
8 double x_, y_; // real and imaginary parts
9 };
10
11 class ComplexFloat {
12 public:
13 ComplexFloat(float x = 0.0f, float y = 0.0f) : x_(x), y_(y) {}
14 float real() const { return x_; }
15 float imag() const { return y_; }
16 // ...
17 private:
18 float x_, y_; // real and imaginary parts
19 };

both of above classes are special cases of following class parameterized


on type T:
1 class Complex {
2 public:
3 Complex(T x = T(0), T y = T(0)) : x_(x), y_(y) {}
4 T real() const { return x_; }
5 T imag() const { return y_; }
6 // ...
7 private:
8 T x_, y_; // real and imaginary parts
9 };

again, would be nice if we did not have to repeatedly type, debug, test,
and maintain nearly identical code
Class Templates
class template is family of classes parameterized on one or more
parameters
each template parameter can be: non-type (e.g., integral constant), type,
template, or parameter pack (in case of variadic template)
syntax has general form:
template <parameter list> class declaration
parameter list: parameter list for class
class declaration: class/struct declaration or definition
example:
// declaration of class template
template <class T, unsigned int size>
class MyArray;
// definition of class template
template <class T, unsigned int size>
class MyArray {
// ...
T array_[size];
};
MyArray <double, 100> x;
Class Templates (Continued)
compiler only generates code for class template when it is instantiated
(i.e., used)
since compiler only generates code for class template when it is
instantiated, definition of template must be visible at point where
instantiated
consequently, class template code usually placed in header file
template code only needs to pass basic syntax checks, unless actually
instantiated
compile errors related to class templates can often be very long and
difficult to parse (especially, when template class has parameters that are
template classes which, in turn, have parameters that are template
classes, and so on)
Class Template Example
1
// complex number class template
2
template <class T >
3
class Complex {
4 public:
5 Complex(T x = T(0), T y = T(0)) :
6 x_(x), y_(y) {}
7 T real() const {
8 return x_;
9 }
10 T imag() const {
11 return y_;
12 }
13 // ...
14 private:
15 T x_; // real part
16 T y_; // imaginary part
17 };
18
19 Complex <int> zi;
20 Complex <double> zd;
Class-Template Default Parameters

class template parameters can have default values


example:
template <class T = int, unsigned int size = 2>
struct MyArray {
T data[size];
};

MyArray <> a; // MyArray<int, 2>


MyArray <double> b; // MyArray<double, 2>
MyArray<double, 10> b; // MyArray<double, 10>
Qualified Dependent Names
qualified dependent name assumed not to name type, unless preceded by
typename keyword
in following example, note use of typename keyword:
1 #include <vector>
2
3 template <class T> class Vector {
4 public:
5 using Coordinate = typename T::Coordinate;
6 using Distance = typename T::Distance;
7
Vector(const std::vector <Coordinate >& coords) :
8
coords_(coords) {}
9 Distance squaredLength() const {
10 Distance d = Distance(0);
11 for (typename
12 std::vector<Coordinate >::const_iterator i =
13 coords_.begin(); i != coords_.end(); ++i) {
14 typename std::vector<Coordinate >::value_type
15 x = *i;
16 d += x * x;
17 }
18 return d ;
19 }
20 // ...
21 private:
22 std::vector <Coordinate > coords_;
23 }
Template Template Parameter Example
1 #include <vector >
2 #include <list >
3 #include <deque >
4 #include <memory >
5
6 template <templat e <class, class> class Container ,
7 typename Value>
8 class Stack {
9 public:
10 // ...
11 private:
12 Container <Value, std::allocator <Value>> data_;
13
};
14
15
int main() {
16
Stack<std::vector, int> s1;
17
Stack<std::list, int> s2;
18
Stack<std::deque, int> s3;
19 }
Derived Classes
sometimes, want to express commonality between classes
want to create new class from existing class by adding new members or
replacing (i.e., hiding/overriding) existing members
can be achieved through language feature known as inheritance
generate new class with all members of already existing class, excluding
special member functions (i.e., constructors, assignment operators, and
destructor)
new class called derived class and original class called base class
derived class said to inherit from base class
can add new members (not in base class) to derived class
can hide or override member functions from base class with new version
syntax for specifying derived class:
class derived class : base class specifiers

derived class is name of derived class; base class specifiers provide


base-class information
Derived Classes (Continued)

can more clearly express intent by explicitly identifying relationship between


classes
can facilitate code reuse by leverage existing code
interface inheritance: allow different derived classes to be used
interchangeably through interface provided by common base class
implementation inheritance: save implementation effort by sharing
capabilities provided by base class
Person Class
1 #include <string>
2
3 class Person {
4 public:
5 Person(const std::string& family_name ,
6 const std::string& given_name) :
7 family_name_(family_name), given_name_(given_name) {}
8 std::string family_name() const {return family_name_;}
9 std::string given_name() const {return given_name_;}
10 std::string full_name() const
11 {return family_name_ + ", " + given_name_;}
12 // ...
13 private:
14 std::string family_name_;
15 std::string given_name_;
16 };
Student Class Without Inheritance
1 #include <string>
2
3 class Student {
4 public:
5 Student(const std::string& family_name ,
6 const std::string& given_name) :
7 family_name_(family_name), given_name_(given_name) {}
8 // NEW
9 std::string family_name() const {return family_name_;}
10 std::string given_name() const {return given_name_;}
11 std::string full_name() const
12 {return family_name_ + ", " + given_name_;}
13 std::string student_id() {return student_id_;} // NEW
14 private:
15 std::string family_name_;
16 std::string given_name_;
17 std::string student_id_; // NEW
18 };
Student Class With Inheritance
1 // include definition of Person class here
2
3 class Student : public Person {
4 public:
5 Student(const std::string& family_name ,
6 const std::string& given_name ,
7 const std::string& student_id) :
8 Person(family_name , given_name),
9 student_id_(student_id) {}
10 std::string student_id() {return student_id_;}
11 private:
12 std::string student_id_;
13 };
Complete Inheritance Example
1 #include <string>
2
3 class Person {
4 public:
5 Person(const std::string& family_name ,
6 const std::string& given_name) :
7 family_name_(family_name), given_name_(given_name) {}
8 std::string family_name() const {return family_name_;}
9 std::string given_name() const {return given_name_;}
10 std::string full_name() const
11 {return family_name_ + ", " + given_name_;}
12 // ... (including virtual destructor)
13 private:
14 std::string family_name_;
15 std::string given_name_;
16 };
17
18 class Student :public Person {
19 public:
20 Student(const std::string& family_name ,
21 const std::string& given_name ,
22 const std::string& student_id) :
23 Person(family_name , given_name),
24 student_id_(student_id) {}
25 std::string student_id() {return student_id_;}
26 private:
27
28 };
Class Hierarchies
inheritance relationships between classes form what is called class
hierarchy
often class hierarchy represented by directed (acyclic) graph, where nodes
correspond to classes and edges correspond to inheritance relationships
class definitions:
class A { /* ... */ };
class B : public A { /* ... */ };
class C : public A { /* ... */ };
class D : public B { /* ... */ };
class E : public B { /* ... */ };

inheritance diagram:
A

B C

D E
Class Hierarchy Example
class definitions:
class Person { /* ... */ };
class Employee : public Person { /* ... */ };
class Student : public Person { /* ... */ };
class Alumnus : public Person { /* ... */ };
class Faculty : public Employee { /* ... */ };
class Staff : public Employee { /* ... */ };
class Grad : public Student { /* ... */ };
class Undergrad : public Student { /* ... */ };
inheritance diagram:
Person

Employee Student Alumnus

Faculty Staff Undergrad Grad

each of Employee, Student, and Alumnus is a Person; each of Faculty


and Staff is an Employee; each of Undergrad and Grad is a Student
Member Access Specifiers: protected
earlier, introduced public and private access specifiers for class
members
in context of inheritance, another access specifier becomes relevant,
namely, protected
member declared in protected section of class can only be accessed by
member functions and friends of that class; and
by member functions and friends of derived classes
protected members used to provide developers of derived classes access
to some inner workings of base class without exposing such inner
workings to everyone
usually, bad idea to use protected access for data members (for similar
reasons that using public access for data members is usually bad)
protected access usually employed for function members
Types of Inheritance
three types of inheritance with respect to access protection: public,
protected, and private
these three types of inheritance differ in terms of accessibility, in derived
class, of members inherited from base class
private parts of base class are always inaccessible in derived class,
regardless of whether public, protected, or private inheritance used
if this were not case, all access protection could simply be bypassed by
using inheritance
access specifiers for members accessible in derived class chosen as
follows:

Access Specifier in Access Specifier in Derived Class


Base Class Public Protected Private
Inheritance Inheritance Inheritance
public public protected privat
protectd protected protected privat
Types of Inheritance (Continued)

for struct, defaults to public inheritance


for class, defaults to private inheritance
public and protected/private inheritance have different use cases
Inheritance and Member Access Example
1 class Base {
2 public:
3 void f();
4 protected:
5 void g();
6 private:
7 int x;
8 };
9
10 class Derived_1 : public Base {
11 // f is public
12 // g is protected
13 // x is not accessible from Derived_1
14 };
15
16 class Derived_2 : protected Base {
17 // f is protected
18 // g is protected
19 // x is not accessible from Derived_2
20 };
21
22 class Derived_3 : private Base {
23
// f is private
24
// g is private
25 // x is not accessible from Derived_3
26 };
Public Inheritance Example
1 class Base {
2 public:
3 void func_1();
4 protected:
5 void func_2();
6 private:
7 int x_;
8 };
9
10 class Derived : public Base {
11 public:
12 void func_3() {
13 func_1(); // OK
14 func_2(); // OK
15 x_ = 0; // ERROR: inaccessible
16 }
17 };
18
19 struct Widget : public Derived {
20 void func_4() { func_2(); } // OK
21 };
22
23 int main() {
24 Derived d;
25 d.func_1(); // OK
26 d.func_2(); // ERROR: inaccessible
27 d.x_ = 0; // ERROR: inaccessible
28 }
Protected Inheritance Example
1 class Base {
2 public:
3 void func_1();
4 protected:
5 void func_2();
6 private:
7 int x_;
8 };
9
10 class Derived : protected Base {
11 public:
12
void func_3() {
13
func_1(); // OK
14 func_2(); // OK
15 x_ = 0; // ERROR: inaccessible
16 }
17 };
18
19 struct Widget : public Derived {
20 void func_4() { func_2(); } // OK
21 };
22
23 int main() {
24 Derived d; // OK: defaulted constructor is public
25 d.func_1(); // ERROR: inaccessible
26 d.func_2(); // ERROR: inaccessible
27 d.x_ = 0; // ERROR: inaccessible
28 }
Private Inheritance Example
1 class Base {
2 public:
3 void func_1();
4 protected:
5 void func_2();
6 private:
7 int x_;
8 };
9
10 class Derived : private Base {
11 public:
12 void func_3(){
13 func_1(); // OK
14 func_2(); // OK
15 x_ = 0; // ERROR: inaccessible
16 }
17 };
18
19 struct Widget : public Derived {
20 void func_4() { func_2(); } // ERROR: inaccessible
21 };
22
23 int main() {
24 Derived d; // OK: defaulted constructor is public
25 d.func_1(); // ERROR: inaccessible
26 d.func_2(); // ERROR: inaccessible
27 d.x_ = 0; // ERROR: inaccessible
28 }
Public Inheritance

public inheritance is inheritance in traditional object-oriented programming


sense
public inheritance models an is-a relationship (i.e., derived class object is a
base class object)
most common form of inheritance
inheritance relationship visible to all code
Public Inheritance Example
1 #include <string>
2
3 class Person {
4 public:
5 Person(const std::string& family_name , const std::string&
6 given_name) : family_name_(family_name),
7 given_name_(given_name) {}
8 std::string family_name() const
9 {return family_name_;}
10 std::string given_name() const
11 {return given_name_;}
12 std::string full_name() const
13 {return family_name_ + ", " + given_name_;}
14 private:
15 std::string family_name_;
16 std::string given_name_;
17 };
18
19 class Student : public Person {
20 public:
21 Student(const std::string& family_name , const std::string&
22 given_name , const std::string& student_id) :
23 Person(family_name , given_name), student_id_(student_id)
24 std::string student_id()
25 {return student_id_;}
26 private:
27 std::string student_id_;
28 };
Protected and Private Inheritance
protected and private inheritance not inheritance in traditional
object-oriented programming sense (i.e., no is-a relationship)
form of implementation inheritance
implemented-in-terms-of relationship (i.e., derived class object
implemented in terms of a base class object)
in case of protected inheritance, inheritance relationship only seen by
derived classes and their friends and class itself and its friends
in case of private inheritance, inheritance relationship only seen by class
itself and its friends (not derived classes and their friends)
except in special circumstances, normally bad idea to use inheritance for
composition
one good use case for private/protected inheritance is in policy-based
design, which exploits empty base optimization (EBO)
Inheritance and Constructors
by default, constructors not inherited
often, derived class introduces new data members not in base class
since base-class constructors cannot initialize derived-class data
members, inheriting constructors from base class by default would be bad
idea (e.g., could lead to uninitialized data members)
in some cases, however, base-class constructors may be sufficient to
initialize derived-class objects
in such cases, can inherit all non-special base-class constructors with
using statement
special constructors (i.e., default, copy, and move constructors) cannot be
inherited
constructors to be inherited with using statement may still be hidden by
constructors in derived class
Inheriting Constructors Example
1 class Base {
2 public:
3 Base() : i_(0.0), j_(0) {}
4 Base(int i) : i_(i), j_(0) {}
5 Base(int i, int j) : i_(i), j_(j) {}
6 // ... (other non-constructor members)
7 private:
8 int i_, j_;
9 };
10
11 class Derived : public Base {
12 public:
13 // inherit non-special constructors from Base
14 // (default constructor not inherited)
15 using Base::Base;
16 // default constructor is implicitly declared and
17 // not inherited
18 };
19
20 int main() {
21 Derived a;
22 // invokes non-inherited Derived::Derived()
23 Derived b(42, 42);
24 // invokes inherited Base::Base(int, int)
25 }
Inheriting Constructors Example
1 class Base {
2 public:
3 Base() : i_(0), j_(0), k_(0) {}
4 Base(int i, int j) : i_(i), j_(j), k_(0) {}
5 Base(int i, int j, int k) : i_(i), j_(j), k_(k) {}
6 // ... (other non-constructor members)
7 private:
8 int i_, j_, k_;
9 };
10
11 class Derived : public Base {
12 public:
13 // inherit non-special constructors from Base
14 // (default constructor not inherited)
15 using Base::Base;
16 // following constructor hides inherited constructor
17 Derived(int i, int j, int k) : Base(-i, -j, -k) {}
18 // no implicitly-generated default constructor
19 };
20
21 int main() {
22 Derived b (1, 2);
23 // invokes inherited Base::Base(int, int)
24 Derived c (1, 2, 3);
25 // invokes Derived::Derived(int, int, int)
26 // following would produce compile-time error:
27 // Derived a; // ERROR: no default constructor
28 }
Inheritance, Assignment Operators, and Destructors

by default, assignment operators not inherited (for similar reasons as in case of


constructors)
can inherit all non-special base-class assignment operators with using
statement
copy and move assignment operators cannot be inherited
assignment operators to be inherited with using statement may still be hidden
by assignment operators in derived class
cannot inherit destructor
Inheriting Assignment Operators Example
1 class Base {
2 public:
3 explicit Base(int i) : i_(i) {}
4 Base& operator=(int i) {
5 i_ = i;
6 return *this;
7 }
8 // ...
9 private:
10 int i_;
11 };
12
13 class Derived : public Base {
14 public:
15 // inherit non-special constructors
16 using Base::Base;
17 // inherit non-special assignment operators
18 using Base::operator=;
19 // ...
20 };
21
22 int main() {
23 Derived d(0);
24 // invokes inherited Base::Base(int)
25
d = 42;
26 // invokes inherited Base::operator=(int)
27
}
Construction and Destruction Order

during construction of object, all of its base class objects constructed first
order of construction:
1
base class objects as listed in type definition left to right
2
data members as listed in type definition top to bottom
3
constructor body
order of destruction is exact reverse of order of construction, namely:
1 destructor body
2 data members as listed in type definition bottom to top
3 base class objects as listed in type definition right to left
Order of Construction
1 #include <vector>
2 #include <string>
3
4 class Base {
5 public:
6 Base(int n) : v_(n, 0) {}
7 // ...
8 private:
9 std::vector <char> v_;
10 };
11
12 class Derived : public Base {
13 public:
14 Derived(const std::string& s) : Base(1024), s_(s)
15 { i_ = 0; }
16 // ...
17 private:
18 std::string s_;
19 int i_ ;
20 };
21
22 int main(){
23 Derived d("hello");
24 }
construction order for Derived constructor: 1) Base class object, 2) data
member s_, 3) Derived constructor body (initializes data member i_)
Hiding Base-Class Member Functions in Derived Class
can provide new versions of member functions in derived class to hide
original functions in base class
1 #include <iostream >
2
3 class Fruit {
4 public:
5 void print() const {std::cout << "fruit\n";}
6 };
7
8 class Apple : public Fruit {
9 public:
10 void print() const {std::cout << "apple\n";}
11 };
12
13 class Banana : public Fruit {
14 public:
15 void print() const {std::cout << "banana\n";}
16 };
17
18 int main() {
19 Fruit f ;
20 Apple a ;
21 Banana b ;
22 f.print(); // calls Fruit::print
23 a.print(); // calls Apple::print
24 b.print(); // calls Banana::print
25 }
Upcasting
derived-class object always has base-class subobject
given reference or pointer to derived-class object, may want to find
reference or pointer to corresponding base-class object
upcasting: converting derived-class pointer or reference to base-class
pointer or reference
upcasting allows us to treat derived-class object as base-class object
upcasting always safe in sense that cannot result in incorrect type (since
every derived-class object is also a base-class object)
in case of public inheritance, can upcast without explicit type-cast operator
in case of protected or private inheritance, cannot upcast, except with
C-style cast (which also can bypass access protection)
example:
class Base { /* ... */ };
class Derived : public Base { /* ... */ };
void func() {
Derived d;
Base* bp = &d;
}
Downcasting
downcasting: converting base-class pointer or reference to derived-class
pointer or reference
downcasting allows us to force base-class object to be treated as
derived-class object
downcasting is not always safe (since not every base-class object is
necessarily also derived-class object)
must only downcast when known that object actually has derived type
(except in case of dynamic_cast)
downcasting always requires explicit cast (static_cast for
non-polymorphic case, dynamic_cast for polymorphic case, C-style
cast for either case)
example:
class Base { /* ... (nonpolymorphic) */ };
class Derived : public Base { /* ... */ };
void func() {
Derived d;
Base* bp = &d;
Derived* dp = static_cast<Derived*>(bp);
}
Upcasting/Downcasting Example
1 class Base { /* ... (nonpolymorphic) */ };
2
3 class Derived : public Base { /* ... */ };
4
5 int main() {
6 Base b;
7 Derived d;
8 Base* bp = nullptr;
9 Derived* dp = nullptr;
10 bp = &d;
11 // OK: upcast does not require explicit cast
12 dp = bp;
13 // ERROR: downcast requires explicit cast
14 dp = static_cast<Derived*>(bp);
15 // OK: downcast with explicit cast and
16 // pointer (bp) refers to Derived object
17 Base& br = d;
18 // OK: upcast does not require explicit cast
19 Derived& dr1 = *bp;
20 // ERROR: downcast requires explicit cast
21
Derived& dr2 = *static_cast<Derived*>(bp);
22 // OK: downcast with explicit cast and
23
// object (*bp) is of Derived type
24
dp = static_cast<Derived*>(&b);
25 // BUG: pointer (&b) does not refer to Derived object
26 }
Upcasting Example
1 class Base { /* ... */ };
2
3 class Derived : public Base { /* ... */ };
4
5 void func_1(Base& b) { / ... / }
6 * *
7 void func_2(Base* b) { / ... / }
8 * *
9 int main() {
10 Base b;
11 Derived d;
12 func_1(b);
13
func_1(d); // OK: Derived& upcast to Base&
14
func_2(&b);
15
func_2(&d); // OK: Derived* upcast to Base*
16 }
Inheritance and Overloading

functions do not overload across scopes


can employ using statement to bring base members into scope for
overloading
Inheritance and Overloading Example
1 #include<iostream >
2
3 class Base {
4 public:
5 double f(double d) const {return d ;}
6 // ...
7 };
8
9 class Derived : public Base {
10 public:
11 int f(int i) const {return i;}
12 // ...
13 };
14
15 int main()
16 {
17 Derived d;
18 std::cout << d.f(0) << ’\n’;
19 // calls Derived::f(int) const
20 std::cout << d.f(0.5) << ’\n’;
21 // calls Derived::f(int) const; probably not intended
22 Derived* dp = &d;
23 std::cout << dp->f(0) << ’\n’;
24 // calls Derived::f(int) const
25 std::cout << dp->f(0.5) << ’\n’;
26 // calls Derived::f(int) const; probably not intended
27 }
Using Base Members Example
1 #include<iostream >
2
3 class Base {
4 public:
5 double f(double d) const {return d;}
6 // ...
7 };
8
9 class Derived : public Base {
10 public:
11 using Base::f; // bring Base::f into scope
12 int f (int i ) const {return i ;}
13 // ...
14 };
15
16 int main()
17 {
18 Derived d;
19 std::cout << d.f(0) << ’\n’;
20 // calls Derived::f(int) const
21 std::cout << d.f(0.5) << ’\n’;
22 // calls Base::f(double) const
23 Derived* dp = &d;
24 std::cout << dp->f(0) << ’\n’;
25 // calls Derived::f(int) const
26 std::cout << dp->f(0.5) << ’\n’;
27 // calls Base::f(double) const
28 }
Inheritance, Templates, and Name Lookup
name lookup in templates takes place in two phases:
1 at template definition time
2 at template instantiation time
at template definition time, compiler parses template and looks up any
nondependent names
result of nondependent name lookup must be identical in all instantiations
of template (since, by definition, nondependent name does not depend on
template parameter)
at template instantiation time, compiler looks up any dependent names
results of dependent name lookup can differ from one template
instantiation to another (since, by definition, dependent name depends on
template parameters)
two-phase name lookup can interact with inheritance in ways that can
sometimes lead to unexpected problems in code
may need to add “this->” or employ using statement to make name
dependent (when it would otherwise be nondependent)
Name Lookup Example (Incorrect Code)
1 #include <iostream >
2
3 template <class T>
4 struct Base {
5 using Real = T;
6 Base(Real x_ = Real()) : x(x_) {}
7 void f() {std::cout << x << "\n";};
8 Real x;
9 };
10
11 template <class T>
12 struct Derived : Base<T> {
13 Derived(Real y_ = Real()) : y(y_) {}
14 // ERROR: Real (which is nondependent and looked up at
15 // template definition time) is assumed to be defined
16 // outside class
17 void g() {
18
x = y;
19
// ERROR: x assumed to be object outside class
20
f();
21
// ERROR: f assumed to be function outside class
22
}
23
Real y;
24 };
25
26 int main() {
27 Derived <double> w(0.0);
28 w.g();
29 }
Name Lookup Example (Correct Code)
1 #include <iostream >
2
3 template <class T>
4 struct Base {
5 using Real = T;
6 Base(Real x_ = Real()) : x(x_) {}
7 void f() {std::cout << x << "\n";};
8 Real x;
9 };
10
11 template <class T>
12 struct Derived : Base<T> {
13 using Real = typename Base<T>::Real;
14 // OK: Base<T>::Real dependent
15 Derived(Real y_ = Real()) : y(y_) {}
16 void g() {
17 this->x = y; // OK: this->x dependent
18
this->f(); // OK: this->f() dependent
19 }
20 Real y;
21 };
22
23 int main(){
24 Derived<double> w (0.0);
25 w.g();
26 }
Run-Time Polymorphism
polymorphism is characteristic of being able to assign different meaning
to something in different contexts
polymorphism that occurs at run time called run-time polymorphism
(also known as dynamic polymorphism)
in context of inheritance, key type of run-time polymorphism is
polymorphic function call (also known as dynamic dispatch)
when inheritance relationship exists between two classes, type of
reference or pointer to object may not correspond to actual dynamic (i.e.,
run-time) type of object referenced by reference or pointer
that is, reference or pointer to type T may, in fact, refer to object of type D,
where D is either directly or indirectly derived from T
when calling member function through pointer or reference, may want
actual function invoked to be determined by dynamic type of object
referenced by pointer or reference
function call with this property said to be polymorphic
Virtual Functions
in context of class hierarchies, polymorphic function calls achieved
through use of virtual functions
virtual function is member function with polymorphic behavior
when call made to virtual function through reference or pointer, actual
function invoked will be determined by dynamic type of referenced object
to make member function virtual, add keyword virtual to function
declaration
example:
class Base {
public:
virtual void func(); // virtual function
// ...
};
Virtual Functions (Continued)
once function made virtual, it will automatically be virtual in all derived
classes, regardless of whether virtual keyword is used in derived
classes
therefore, not necessary to repeat virtual qualifier in derived classes
(and perhaps preferable not to do so)
virtual function must be defined in class where first declared unless pure
virtual function (to be discussed shortly)
derived class inherits definition of each virtual function from its base class,
but may override each virtual function with new definition
function in derived class with same name and same set of argument types as
virtual function in base class overrides base class version of virtual function
Virtual Function Example
1 #include <iostream>
2 #include <string>
3
4 class Person {
5 public:
6 Person(const std::string& family, const std::string& given) :
7 family_(family), given_(given) {}
8 virtual void print() const
9 {std::cout << "person: " << family_ << ’,’ << given_ << ’\n’;}
10 protected:
11 std::string family_; // family name
12 std::string given_; // given name
13 };
14
15 class Student : public Person {
16 public:
17 Student(const std::string& family, const std::string& given,
18 const std::string& id) : Person(family, given), id_(id) {}
19 void print() const { std
20 ::cout << "student: " << family_ << ’,’ << given_ << ’,’ << id_ << ’\n’;
21 }
22 private:
23 std::string id_; // student ID
24 };
25
26 void processPerson(const Person& p) {
27 p.print(); // polymorphic function call
28 // ...
29 }
30
31 int main() {
32
33 Person p("Ritchie", "Dennis");
Student s("Doe", "John", "12345678");
34
processPerson(p); // invokes Person::print
35
36 processPerson(s); // invokes Student::print
}
Override Control: The override Qualifier
when looking at code for derived class, often not possible to determine if
member function intended to override virtual function in base class (or one
of its base classes)
can sometimes lead to bugs where programmer expects member function
to override virtual function when function not virtual
override qualifier used to indicate that member function is expected to
override virtual function in parent class; must come at end of function
declaration
example:
class Person {
public:
virtual void print() const;
// ...
};
class Employee : public Person {
public:
void print() const override; // must be virtual
// ...
};
Override Control: The final Qualifier
sometimes, may want to prevent any further overriding of virtual function
in any subsequent derived classes
adding final qualifier to declaration of virtual function prevents function
from being overridden in any subsequent derived classes
preventing further overriding can sometimes allow for better optimization
by compiler (e.g., via devirtualization)
example:
class A {
public:
virtual void doStuff();
// ...
};
class B : public A {
public:
void doStuff() final; // prevent further overriding
// ...
};
class C : public B {
public:
void doStuff(); // ERROR: cannot override
final Qualifier Example
1 class Worker {
2
public:
3
virtual void prepareEnvelope();
4
// ...
5
};
6
7
class SpecialWorker : public Worker {
8
public:
9 // prevent overriding function responsible for
10 // overall envelope preparation process
11 // but allow functions for individual steps in
12 // process to be overridden
13 void prepareEnvelope() final {
14 stuffEnvelope(); // step 1
15 lickEnvelope(); // step 2
16 sealEnvelope(); // step 3
17 }
18 virtual void stuffEnvelope();
19 virtual void lickEnvelope();
20 virtual void sealEnvelope();
21 // ...
22 };
Constructors, Destructors, and Virtual Functions
except in very rare cases, destructors in class hierarchy need to be virtual
otherwise, invoking destructor through base-class pointer/reference would
only destroy base-class part of object, leaving remainder of derived-class
object untouched
normally, bad idea to call virtual function inside constructor or destructor
dynamic type of object changes during construction and changes again
during destruction
final overrider of virtual function will change depending where in hierarchy
virtual function call is made
when constructor/destructor being executed, object is of exactly that type,
never type derived from it
although semantics of virtual function calls during construction and
destruction well defined, easy to write code where actual overrider not
what expected (and might even be pure virtual)
Problematic Code with Non-Virtual Destructor
1 class Base {
2 public:
3 Base() {}
4 B̃ase() {} // non-virtual destructor
5 // ...
6 };
7
8 class Derived : public Base {
9 public:
10 Derived() : buffer_(new char[10’000]) {}
11 D̃erived() {delete[] buffer_;}
12 // ...
13 private:
14 char* buffer_;
15 };
16
17 void process(Base* bp) {
18 // ...
19 delete bp; // invokes only Base::B̃ase
20 } always
21
22 int main() {
23 process(new Base);
24 process(new Derived); // leaks memory
25 }
Corrected Code with Virtual Destructor
1 class Base {
2 public:
3 Base() {}
4 virtual B̃ase() {} // virtual destructor
5 // ...
6 };
7
8 class Derived : public Base {
9 public:
10 Derived() : buffer_(new char[10’000]) {}
11 D̃erived() {delete[] buffer_;}
12 // ...
13 private:
14 char* buffer_;
15 };
16
17 void process(Base* bp) {
18 // ...
19 delete bp; // destructor polymorphically
20 } invokes
21
22 int main() {
23 process(new Base);
24 process(new Derived);
25 }
Preventing Creation of Derived Classes
in some situations, may want to prevent deriving from class
language provides means for accomplishing this
in class/struct declaration, after name of class can add keyword final to
prevent deriving from class
example:
class Widget final { /* ... */ };
class Gadget : public Widget { /* ... */ };
// ERROR: cannot derive from Widget

might want to prevent deriving from class with destructor that is not virtual
preventing derivation can sometimes also facilitate better compiler
optimization (e.g., via devirtualization)
might want to prevent derivation so that objects can be copied safely
without fear of slicing
Covariant Return Type
in some special cases, language allows relaxation of rule that type of
overriding function f must be same as type of virtual function f overrides
in particular, requirement that return type be same is relaxed
return type of derived-class function is permitted to be type derived
(directly or indirectly) from return type of base-class function
this relaxation of return type more formally known as covariant return
type
case of pointer return type: if original return type B*, return type of
overriding function may be D*, provided B is public base of D (i.e., may
return pointer to more derived type)
case of reference return type: if original return type B& (or B&&), return
type of overriding function may be D& (or D&&), provided B is public base of
D (i.e., may return reference to more derived type)
covariant return type can sometimes be exploited in order to avoid need
for type casts
Covariant Return Type Example: Cloning
1 class Base {
2 public:
3 virtual Base* clone() const {
4 return new Base(*this);
5 }
6 // ...
7 };
8
9 class Derived : public Base {
10 public:
11 // use covariant return type
12 Derived* clone() const override {
13 return new Derived(*this);
14 }
15 // ...
16 };
17
18 int main() {
19 Derived* d = new Derived;
20 Derived* d2 = d->clone();
21 // OK: return type is Derived*
22
// without covariant return type, would need cast:
23 // Derived* d2 = static_cast<Derived*>(d->clone());
24 }
Pure Virtual Functions
sometimes desirable to require derived class to override virtual function
pure virtual function: virtual function that must be overridden in every
derived class
to declare virtual function as pure, add “= 0” at end of declaration
example:
class Widget {
public:
virtual void doStuff() = 0; // pure virtual
// ...
};

pure virtual function can still be defined, although likely only useful in case
of virtual destructor
Abstract Classes
class with one or more pure virtual functions called abstract class
cannot directly instantiate objects of abstract class (can only use them as
base class objects)
class that derives from abstract class need not override all of its pure
virtual methods
class that does not override all pure virtual methods of abstract base class will
also be abstract
most commonly, abstract classes have no state (i.e., data members) and used
to provide interfaces, which can be inherited by other classes
if class has no pure virtual functions and abstract class is desired, can
make destructor pure virtual (but must provide definition of destructor
since invoked by derived classes)
Abstract Class Example
1 #include <cmath>
2
3 class Shape {
4 public:
5 virtual bool isPolygon() const = 0;
6 virtual float area() const = 0;
7 virtual S̃hape() {};
8 };
9
10 class Rectangle : public Shape {
11 public:
12 Rectangle(float w, float h) : w_(w), h_(h) {}
13
bool isPolygon() const override {return true;}
14
float area() const override {return w_ * h_;}
15
private:
16 float w_ ; // width of rectangle
17 float h_ ; // height of rectangle
18 };
19
20
class Circle : public Shape {
21
public:
22 Circle(float r) : r_(r) {}
23
float area() const override {return M_PI * r_ * r_;}
24 bool isPolygon() const override {return false;}
25 private:
26 float r_; // radius of circle
27 };
Pure Virtual Destructor
Example
1 class Abstract {
2 public:
3 virtual Ãbstract() = 0; // pure virtual destructor
4 // ... (no other virtual functions)
5 };
6
7 inline Abstract::Ãbstract()
8 { /* possibly empty */ }
The dynamic_cast Operator
often need to upcast and downcast (as well as cast sideways) in
inheritance hierarchy
dynamic_cast can be used to safely perform type conversions on
pointers and references to classes
syntax: dynamic_cast<T>(expr)
types involved must be polymorphic (i.e., have at least one virtual
function)
inspects run-time information about types to determine whether cast can
be safely performed
if conversion is valid (i.e., expr can validly be cast to T), casts expr to type
T and returns result
if conversion is not valid, cast fails
if expr is of pointer type, nullptr is returned upon failure
if expr is of reference type, std::bad_cast exception is thrown upon
failure (where exceptions are discussed later)
dynamic_cast Example
1 #include <cassert>
2
3 class Base {
4 public:
5 virtual void doStuff() { /* ... */ };
6 // ...
7 };
8
9 class Derived1 : public Base { /* ... */ };
10 class Derived2 : public Base { /* ... */ };
11
12 bool isDerived1(Base& b) {
13 return dynamic_cast<Derived1*>(&b) != nullptr;
14 }
15
16 int main() {
17 Base b ;
18 Derived1 d1;
19 Derived2 d2;
20 assert(isDerived1(b) == false);
21 assert(isDerived1(d1) == true);
22 assert(isDerived1(d2) == false);
23 }
Cost of Run-Time Polymorphism
typically, run-time polymorphism does not come without run-time cost in
terms of both time and memory
in some contexts, cost can be significant
typically, virtual functions implemented using virtual function table
each polymorphic class has virtual function table containing pointers to all
virtual functions for class
each polymorphic class object has pointer to virtual function table
memory cost to store virtual function table and pointer to table in each
polymorphic object
in most cases, impossible for compiler to inline virtual function calls since
function to be called cannot be known until run time
each virtual function call is made through pointer, which adds overhead
Multiple Inheritance
language allows derived class to inherit from more than one base class
multiple inheritance (MI): deriving from more than one base class
although multiple inheritance not best solution for most problems, does
have some compelling use cases
one compelling use case is for inheriting interfaces by deriving from
abstract base classes with no data members
when misused, multiple inheritance can lead to very convoluted code in
multiple inheritance contexts, ambiguities in naming can arise
for example, if class Derived inherits from classes Base1 and Base2, each of
which have member called x, name x can be ambiguous in some contexts
scope resolution operator can be used to resolve ambiguous names
C++ Standard Library

C++ standard library provides huge amount of functionality (orders of


magnitude more than C standard library)
uses std namespace (to avoid naming conflicts)
well worth effort to familiarize yourself with all functionality in library in order
to avoid writing code unnecessarily
C++ Standard Library (Continued)
functionality can be grouped into following sublibraries:
1 language support library (e.g., exceptions, memory management)
2 diagnostics library (e.g., assertions, exceptions, error codes)
3 general utilities library (e.g., functors, date/time)
4 strings library (e.g., C++ and C-style strings)
5 localization library (e.g., date/time formatting and parsing, character
classification)
6 containers library (e.g., sequence containers and associative containers)
7 iterators library (e.g., stream iterators)
8 algorithms library (e.g., searching, sorting, merging, set operations, heap
operations, minimum/maximum)
9 numerics library (e.g., complex numbers, math functions)
10 input/output (I/O) library (e.g., streams)
11 regular expressions library (e.g., regular expression matching)
12 atomic operations library (e.g., atomic types, fences)
13 thread support library (e.g., threads, mutexes, condition variables, futures)
Commonly-Used Header Files
Language-Support Library
Header File Description
cstdlib run-time support, similar to stdlib.h
from C (e.g., exit)
limits properties of fundamental types (e.g.,
numeric_limits)
exception exception handling
support (e.g.,
set_terminate, current_exception)
initializer_list initializer_list class template

Diagnostics Library
Header File Description
cassert assertions (e.g., assert)
stdexcept predefined exception types (e.g.,
invalid_argument, domain_error,
out_of_range)
Commonly-Used Header Files (Continued 1)
General-Utilities Library
Header File Description
utility basic function and class templates (e.g., swap,
move, pair)
memory memory management (e.g.,
unique_ptr,
shared_ptr, addressof)
functional functors (e.g., less, greater)
type_traits type traits (e.g., is_integral, is_reference)

chrono clocks (e.g., system_clock,


steady_clock, high_resolution_clock)

Strings Library
Header File Description
string C++ string classes (e.g., string)
cstring C-style strings, similar to string.hfrom C (e.g., strlen)
cctype character classification, similar to ctype.h from C (e.g., isdigit,
isalpha)
Commonly-Used Header Files (Continued 2)

Containers, Iterators, and Algorithms Libraries


Header File Description
array array class
vector vector class
deque deque class
list list class
set set classes (i.e., set, multiset)
map map classes (i.e., map, multimap)
unordered_set unordered set classes (i.e.,
unordered_set, unordered_multiset)
unordered_map unordered map classes (i.e.,
unordered_map, unordered_multimap)
iterator iterators (e.g., reverse_iterator,
back_inserter)
algorithm algorithms (e.g., min, max, sort)
Commonly-Used Header Files (Continued 3)

Numerics Library
Header File Description
cmath C math library, similar to math.h from C (e.g., sin, cos)
complex complex numbers (e.g., complex)
random random number generation
(e.g.,
uniform_int_distribution,
uniform_real_distribution,
normal_distribution)
Commonly-Used Header Files (Continued 4)
I/O Library
Header File Description
iostream iostream objects (e.g., cin, cout, cerr)
istream input streams (e.g., istream)
ostream output streams (e.g., ostream)
ios base classes and other declarations for
streams (e.g., ios_base, hex, fixed)
fstream file streams (e.g., fstream)
sstream string streams (e.g., stringstream)
iomanip manipulators (e.g., setw, setprecision)

Regular-Expressions Library
Header File Description
regexp regular expressions (e.g., basic_regex)
Commonly-Used Header Files (Continued 5)

Atomic-Operations and Thread-Support Libraries


Header File Description
atomic atomics (e.g., atomic)
thread threads (e.g., thread)
mutex mutexes (e.g., mutex,
recursive_mutex,
timed_mutex)
condition_variab condition variables (e.g.,
le condition_variable)
future futures (e.g., future, shared_future,
promise)
Standard Template Library (STL)
large part of C++ standard library is collection of class/function templates
known as standard template library (STL)
STL comprised of three basic building blocks:

1 containers
2 iterators
3 algorithms

containers store elements for processing (e.g., vector)


iterators allow access to elements for processing (which are often, but not
necessarily, in containers)
algorithms perform actual processing (e.g., search, sort)
Containers
container: class that represents collection/sequence of elements usually
container classes are template classes
sequence container: collection in which every element has certain position
that depends on time and place of insertion
examples of sequence containers include:
array (fixed-size array) vector
(dynamic-size array) list
(doubly-linked list)
ordered/unordered associative container: collection in which position of element
in depends on its value or associated key and some predefined sorting/hashing
criterion
examples of associative containers include:
set (collection of unique keys, sorted by key)
map (collection of key-value pairs, sorted by key, keys are unique)
Sequence Containers and Container Adapters
Sequence Containers
Name Description
array fixed-size array
vector dynamic-size array
deque double-ended queue
forward_lis singly-linked list
t
list doubly-linked list

Container Adapters
Name Description
stack stack
queue FIFO queue
priority_que priority queue
ue
Associative Containers
Ordered Associative Containers
Name Description
set collection of unique keys, sorted by key
map collection of key-value pairs, sorted by key, keys are unique
multise collection of keys, sorted by key, duplicate keys allowed
t
multima collection of key-value pairs, sorted by key, duplicate keys al-
p lowed
Unordered Associative Containers
Name Description
unordered_set collection of unique keys, hashed by key
unordered_map collection of key-value pairs, hashed by key, keys are
unique
unordered_multis collection of keys, hashed by key, duplicate keys al-
et lowed)
unordered_multim collection of key-value pairs, hashed by key, duplicate
ap keys allowed
Typical Sequence Container Member Functions
some member functions typically provided by sequence container classes
listed below (where T denotes name of container class)

Function Description
T() create empty container (default constructor)
T(const T&) copy container (copy constructor)
T(T&&) move container (move constructor)
T̃ destroy container (including its elements)
empty test if container empty
size get number of elements in container
push_back insert element at end of container
clear remove all elements from container
operator= assign all elements of one container to other
operator[] access element in container
Container Example
1
#include <iostream >
2
#include <vector >

3
4
int main() {
5
std::vector <int>
values ;
6
7
// append elements with values 0 to 9
8 for (int i = 0; i < 10; ++i) {
9 values.push_back(i);
10 }
11
12 // print each element followed by space
13 for (int i = 0; i < values.size(); ++i) {
14 std::cout << values[i] << ’ ’;
15 }
16 std::cout << ’\n’;
17 }
18
19 /* This program produces the following output:
20 0 1 2 3 4 5 6 7 8 9
21 */
The vector Class Template
dynamically-sized one-dimensional array type, where type of array
elements and storage allocator specified by template parameters
vector declared as:
template <class T, class Allocator = allocator <T>>
class vector;

T: type of elements in vector


Allocator: type of object used to handle storage allocation (unless
custom storage allocator needed, use default allocator<T>)
what follows only intended to provide overview of vector
for additional details on vector, see:
http://www.cplusplus.com/reference/stl/vector
http://en.cppreference.com/w/cpp/container/vector
Member Types
Member Type Description
value_type T (i.e., element type)
allocator_type Allocator (i.e., allocator)
size_type type used for measuring size (typically unsigned in-
tegral type)
difference_type type used to measure distance (typically signed in-
tegral type)
reference value_type&
const_reference const value_type&
pointer allocator_traits<Allocator>::pointer
const_pointer allocator_traits<Allocator>::
const_pointer
iterator
random-access iterator type
const_iterator const random-access iterator type
reverse_iterator reverse iterator type
(reverse_iterator<iterator>)
const_reverse_iterator const reverse iterator type
(reverse_iterator<const_iterator>)
Member Functions
Construction, Destruction, and Assignment
Member Name Description
constructor construct vector (overloaded)
destructor destroy vector
operator= assign vector

Iterators
Member Name Description
begin return iterator to beginning
end return iterator to end
cbegin return const iterator to beginning
cend return const iterator to end
rbegin return reverse iterator to beginning
rend return reverse iterator to end
crbegin return const reverse iterator to beginning
crend return const reverse iterator to end
Member Functions (Continued 1)
Capacity
Member Name Description
empty test if vector is empty
size return size
max_size return maximum size
capacity return allocated storage capacity
reserve request change in capacity
shrink_to_fit shrink to fit

Element Access
Member Name Description
operator[] access element (no bounds checking)
at access element (with bounds checking)
front access first element
back access last element
data return pointer to start of element data
Member Functions (Continued 2)
Modifiers
Member Name Description
clear clear content
assign assign vector content
insert insert elements
emplace insert element, constructing in place
push_back add element at end
emplace_bac insert element at end, constructing in place
k
erase erase elements
pop_back delete last element
resize change size
swap swap content of two vectors

Allocator
Member Name Description
get_allocator get allocator used by vector
Invalidation of References, Iterators,
and Pointers
capacity: total number of elements that vector could hold without
requiring reallocation of memory
any operation that causes reallocation of memory used to hold elements
of vector invalidates all iterators, references, and pointers referring to
elements in vector
any operation that changes capacity of vector causes reallocation of
memory
any operation that adds or deletes elements can invalidate references,
iterators, and pointers
operations that can potentially invalidate references, iterators, and
pointers to elements in vector include:
insert, erase, push_back, pop_back, emplace, emplace_back,
resize, reserve, operator=, assign, clear, shrink_to_fit, swap
(past-the-end iterator only)
Iterator Invalidation Example
start denotes pointer to first element in array holding vector elements
i is iterator for vector (e.g., vector<T>::const_iterator, vector<T>::iterator)
initial vector with three elements and capacity of three:

push_back(d) results in new larger array being allocated, contents of old array
copied to new one, and then new element added:

old array is deallocated, iterator i is now invalid:


vector Example: Constructors
std::vector<double> v0;
// empty vector
std::vector<double> v1(10);
// vector with 10 elements, default constructed
// (which for double means uninitialized)
std::vector<double> v2(10, 5.0);
// vector with 10 elements, each initialized to 5.0
std::vector<int> v3{1, 2, 3};
// vector with 3 elements: 1, 2, 3
// std::initializer_list (note brace brackets)
Vector Example: Iterators
#include <iostream >
1
2
vector Example:
#include <vector>
Iterators
3
4 int main() {
5 std::vector <int> v{0, 1, 2, 3};
6 for (auto& i : v) {++i;}
7 for (auto i : v) {
8 std::cout << ’ ’ << i;
9 }
10 std::cout << ’\n’;
11 for (auto i = v.begin(); i != v.end(); ++i) {
12 --(*i);
13 }
14 for (auto i = v.cbegin(); i != v.cend(); ++i) {
15 std::cout << ’ ’ << *i;
16 }
17 std::cout << ’\n’;
18 for (auto i = v.crbegin(); i != v.crend(); ++i) {
19 std::cout << ’ ’ << *i;
20 }
21 std::cout << ’\n’;
22 }

program output: C++


1 2 3 4
0 1 2 3
3 2 1 0
vector Example
1 #include <iostream>
2 #include <vector>
3
4 int main() {
5 std::vector<double> values;
6 // ...
7
8 // Erase all elements and then read elements from
9 // standard input.
10 values.clear();
11 double x;
12 while (std::cin >> x) {
13 values.push_back(x);
14 }
15 std::cout << "number of values read: " <<
16 values.size() << ’\n’;
17
18 // Loop over all elements and print the number of
19 // negative elements found.
20 int count = 0;
21 for (auto i = values.cbegin(); i != values.cend(); ++i) {
22 if (*i < 0.0) {
23 ++count;
24 }
25 }
26 std::cout << "number of negative values: " << count <<
27 ’\n’;
28 }
vector Example: Emplace
1 #include <iostream >
2 #include <vector>
3
4 int main() {
5 std::vector<std::vector <int>> v{{1, 2, 3}, {4, 5, 6}};
6 v.emplace_back(10, 0);
7 // The above use of emplace_back is more efficient than:
8 // v.push_back(std::vector<int>(10, 0));
9 for (const auto& i : v) {
10 for (const auto& j : i) {
11 std::cout << ’ ’ << j;
12 }
13 std::cout << ’\n’;
14 }
15 }

program output:
1 2 3
4 5 6
0 0 0 0 0 0 0 0 0 0
Example with vector and auto
vector<int>s;
s.push_back(11);
s.push_back(22);
s.push_back(33);
s.push_back(55);
for (vector<int>::iterator it = s.begin(); it!=s.end(); it++) {
cout << *it << endl;
}

for (auto it = s.begin(); it != s.end(); it++) {


cout << *it << endl;
}

for (auto& it : s) {
cout << it << endl;
}
The map Class Template
sorted associative container that contains key-value pairs with unique
keys. Keys are sorted by using the comparison function Compare
map declared as:
template<class Key, class T, class Compare =
std::less<Key>, class Allocator =
std::allocator<std::pair<const Key, T> >
> class map;
Key: typeof keyin map
T: type of elements in map
Compare: object to compare keys for sorting
Allocator: type of object used to handle storage allocation (unless
custom storage allocator needed, use default)
what follows only intended to provide overview of map
for additional details on map, see:
http://www.cplusplus.com/reference/map/map/
http://en.cppreference.com/w/cpp/container/map
Member Types
Member Type Description
key_type The first template parameter (Key)
mapped_type The second template parameter (T)
value_type pair<const key_type,mapped_type>
key_compare The third template parameter (Compare)
value_compare Nested function class to compare elements
allocator_type The fourth template parameter (Alloc)
reference value_type&
const_reference const value_type&
pointer allocator_traits<allocator_type>::pointer

const_pointer allocator_traits<allocator_type>::const_pointer

iterator bidirectional iterator to value_type


const_iterator const bidirectional iterator to const value_type
reverse_iterator reverse iterator type reverse_iterator<iterator>

const_reverse_iterator
const reverse iterator
typereverse_iterator<const_iterator>
Member Functions
Construction, Destruction, and Assignment
Member Name Description
constructor construct map
destructor destruct map
operator= copy container content

Iterators
Member Name Description
begin Return iterator to beginning
end Return iterator to end
rbegin Return reverse iterator to reverse beginning
rend Return reverse iterator to reverse end
cbegin Return const_iterator to beginning
cend Return const_iterator to end
crbegin Return const_reverse_iterator to reverse beginning
crend Return const_reverse_iterator to reverse end
Member Functions (Continued 1)
Capacity
Member Name Description
empty checks whether the container is empty
size returns the number of elements
returns the maximum possible number of
max_size elements
Element Access
Member Name Description
access specified element with bounds
at checking
operator[] access specified element
Member Functions (Continued 2)
Modifiers
Member Name Description
clear clears the contents
insert inserts elements or nodes
inserts an element or assigns to the current
insert_or_assign element if the key already exists
emplace constructs element in-place
emplace_hint constructs elements in-place using a hint
inserts in-place if the key does not exist, does
try_emplace nothing if the key exists
erase erases elements
swap swaps the contents
extract extracts nodes from the container
merge splices nodes from another container
Allocator
Member Name Description
get_allocator returns the associated allocator
map Example: Constructors
// Default constructor
std::map <std::string, double> map1;
// empty map
map1[‘something’] = 69;
map1[‘anything’] = 199;

// Range constructor
std::map<std::string, int> iter(map1.find("anything"),
map1.end());

// Copy constructor
std::map<std::string, int> copied(map1);
map Example: Iterators

#include <iostream>
#include <map>

int main() {
std::map<int, float> num_map;
num_map[4] = 4.13;
num_map[9] = 9.24;
num_map[1] = 1.09;
// calls a_map.begin() and a_map.end()
for (auto it = num_map.begin(); it != num_map.end(); ++it) {
std::cout << it->first << ", " << it->second << '\n';
}
}

C++
map Example
#include <string>
#include <iostream>
#include <map>

int main()
{
std::map<std::string,int> my_map;
my_map["x"] = 11;
my_map["y"] = 23;

auto it = my_map.find("x");
if (it != my_map.end()) std::cout << "x: " << it->second << "\n";

it = my_map.find("z");
if (it != my_map.end()) std::cout << "z1: " << it->second << "\n";

// Accessing a non-existing element creates it


if (my_map["z"] == 42) std::cout << "Oha!\n";

it = my_map.find("z");
if (it != my_map.end()) std::cout << "z2: " << it->second << "\n";
}

Output:
x: 11
z2: 0
map Example: Emplace
#include <iostream>
#include <utility>
#include <string>
#include <map>

int main()
{
std::map<std::string, std::string> m;

// uses pair's move constructor


m.emplace(std::make_pair(std::string("a"), std::string("a")));

// uses pair's converting move constructor


m.emplace(std::make_pair("b", "abcd"));

// uses pair's template constructor


m.emplace("d", "ddd");

// uses pair's piecewise constructor


m.emplace(std::piecewise_construct,
std::forward_as_tuple("c"),
std::forward_as_tuple(10, 'c')); Output:
// as of C++17, m.try_emplace("c", 10, 'c'); can be used a => a
for (const auto &p : m) {
b => abcd
std::cout << p.first << " => " << p.second << '\n'; c => cccccccccc
} d => ddd
}

You might also like