Classes
Definition
A class is a user-defined type. A class consists of members. The members are data members and member
functions. A class is a collection of data and some functionality on that data, wrapped into one. An instance
of a class is called an object.
class MyClass
{
}; // an empty class definition
int main()
{
MyClass o; // object - instance of a class
}
45 Copyright © Slobodan Dmitrovic
Classes
Data members
A class can have a set of some data. These are called member fields.
class MyClass
{
char c;
int x;
double d;
};
Member functions
Similarly, a class can store functions. These are called member functions. They are mostly used to perform
some operations on data fields. To declare a member function of type void called myFunction(), we write:
class MyClass
{
void myFunction();
};
46 Copyright © Slobodan Dmitrovic
Classes
Member function definition
There are two ways to define a member function. The first is to define it inside the class.
class MyClass
{
void myFunction() {
std::cout << "Hello World from a class.";
}
};
The second way is to define a member function outside the class.
class MyClass
{
// member function declaration
void myFunction();
};
// member function definition
void MyClass::myFunction() {
std::cout << "Hello World from a class.";
}
47 Copyright © Slobodan Dmitrovic
Classes
Access specifiers
Member access specifiers determine the access/visibility for class members.
class MyClass
{
public:
// all class members in here
// have public access level
protected:
// all class members in here
// have protected access level
private:
// all class members in here
// have private access level
};
Default visibility/access specifier for a class is private if none of the access specifiers is present.
class MyClass
{
// private access by default
};
48 Copyright © Slobodan Dmitrovic
Classes
Access specifiers
Access specifiers determine who can access class members. A class can access all levels, a derived class
can access public and protected members. An object can access only public members.
public protected private
Class ✓ ✓ ✓
Derived class ✓ ✓
Object ✓
Default visibility/access specifier for a struct is public if none of the access specifiers is present.
struct MyStruct
{
// public access by default
};
49 Copyright © Slobodan Dmitrovic
Classes
Constructors
A constructor is a member function that has the same name as the class, and is used to initialize an object
of a class.
Default constructor
A constructor without parameters or with default parameters set, is called a default constructor. It is a
constructor which can be called without arguments.
#include <iostream>
class MyClass
{
public:
MyClass() { std::cout << "Default constructor invoked." << '\n'; }
};
int main()
{
MyClass o; // invoke a default constructor
}
50 Copyright © Slobodan Dmitrovic
Classes
Member initializer list
An efficient way to initialize an object of a class is to use the constructor’s member initializer list in the
constructor's definition.
class MyClass
{
public:
int x, y;
MyClass(int argx, int argy)
: x{ argx }, y{ argy } // member initializer list
{}
};
int main()
{
MyClass o{ 1, 2 }; // invoke a user-defined constructor
}
A member initializer list starts with a colon symbol, followed by coma separated initialization expressions.
51 Copyright © Slobodan Dmitrovic
Classes
Copy constructor
When we initialize an object of a class with another object of the same class, we invoke a copy
constructor. If we do not provide our copy constructor, the compiler will generate a default copy
constructor.
class MyClass
{
private:
int x, y;
public:
MyClass(int argx, int argy) : x{ argx }, y{ argy } // user provided constructor
{}
};
int main()
{
MyClass o1{ 1, 2 }; // user provided constructor invoked
MyClass o2 = o1; // compiler generated, default copy constructor invoked
}
52 Copyright © Slobodan Dmitrovic
Classes
Copy constructor
An example utilizing a user provided copy constructor with the class_name(const class_name& rhs);
signature:
#include <iostream>
class MyClass
{
private:
int x, y;
public:
MyClass(int argx, int argy) : x{ argx }, y{ argy } {}
MyClass(const MyClass& rhs) : x{ rhs.x }, y{ rhs.y } {// user defined copy ctor
std::cout << "User defined copy constructor invoked.";
}
};
int main()
{
MyClass o1{ 1, 2 };
MyClass o2 = o1; // user defined copy constructor invoked
} 53 Copyright © Slobodan Dmitrovic
Classes
Copy assignment operator
When assigning the value of an object of a class to another object of the same class, we are using the
copy assignment operator.
class MyClass
{
// class code
};
int main()
{
MyClass o1 { // initializers };
MyClass o2;
o2 = o1; // copy assignment operator called
}
The copy assignment operator has the following signature:
MyClass& operator=(const MyClass& rhs);
54 Copyright © Slobodan Dmitrovic
Classes
Copy assignment operator
Defining / overloading the copy assignment operator inside the class.
class MyClass
{
public:
MyClass& operator=(const MyClass& rhs)
{
// implement the copy logic here
return *this;
}
};
The overloaded = operators must return a dereferenced pointer *this at the end.
55 Copyright © Slobodan Dmitrovic
Classes
Copy assignment operator
Defining / overloading the copy assignment operator outside the class.
class MyClass
{
public:
MyClass& operator=(const MyClass& rhs);
};
MyClass& MyClass::operator=(const MyClass& rhs)
{
// implement the copy logic here
return *this;
}
Invoking a copy constructor vs. calling a copy assignment operator.
MyClass o1{ 1, 2 }; MyClass o1{ 1, 2 };
MyClass o2 = o1; // copy constructor MyClass o2;
invoked o2 = o1; //copy assignment operator called
56 Copyright © Slobodan Dmitrovic
Classes
Copy assignment operator example
class MyClass
{
private:
int x, y;
public:
MyClass(int argx = 0, int argy = 0) : x{ argx }, y{ argy } { }
MyClass& operator=(const MyClass& rhs) { // copy assignment operator
x = rhs.x;
y = rhs.y;
return *this;
}
};
int main()
{
MyClass o1{ 1, 2 };
MyClass o2;
o2 = o1; // user defined copy assignment operator called
}
57 Copyright © Slobodan Dmitrovic
Classes
Move semantics
In addition to copying, we can also move the data from one object to the other. We call it a move
semantics. Move semantics is achieved through a move constructor and move assignment operator.
Move constructor
Move constructor accepts an rvalue reference as an argument.
class_name(class_name&& rhs);
Move constructor invocation:
MyClass o1{ 1, 2 };
MyClass o2 = std::move(o1); // move constructor invoked
If no user provided move constructor is present, the compiler will generate a default move constructor,
provided there are:
• no user declared copy constructors
• no user declared copy assignment operators
• no user declared move assignment operators
• no user declared destructors
58 Copyright © Slobodan Dmitrovic
Classes
User defined move constructor example
#include <iostream>
#include <string>
#include <utility>
class MyClass
{
private:
int x;
std::string s;
public:
MyClass(int argx, std::string args) : x{ argx }, s{ args } {}
MyClass(MyClass&& rhs) : x{ std::move(rhs.x) }, s{ std::move(rhs.s) } {
std::cout << "Move constructor invoked." << '\n';
}
};
int main()
{
MyClass o1{ 1, "Some string value" };
MyClass o2 = std::move(o1); // invoking a move constructor
}
59 Copyright © Slobodan Dmitrovic
Classes
Move assignment operator
Move assignment operator is invoked when we declare an object and then assign an rvalue reference to it.
The signature of the move assignment operator is:
class_name& operator=(class_name&& rhs);
Move assignment operator in-class definition:
class MyClass
{
public:
MyClass& operator=(MyClass&& otherobject)
{
// implement the move logic here
return *this;
}
};
Invoked as:
MyClass o1{ initialize_object_1 };
MyClass o2{ initialize_object_2 };
o2 = std::move(o1); // move assignment operator invoked
60 Copyright © Slobodan Dmitrovic
Classes
Move assignment operator example
#include <string>
class MyClass
{
private:
int x;
std::string s;
public:
MyClass(int argx, std::string args) : x{ argx }, s{ args } {}
MyClass& operator=(MyClass&& otherobject) {// move assignment operator
x = std::move(otherobject.x);
s = std::move(otherobject.s);
return *this;
}
};
int main()
{
MyClass o1{ 123, "This is currently in object 1." };
MyClass o2{ 456, "This is currently in object 2." };
o2 = std::move(o1); // move assignment operator invoked
61 Copyright © Slobodan Dmitrovic
}
Classes
Destructor
Destructor is a member function that gets invoked when an object is destroyed. The destructor takes no
parameters and should not be called directly. They can be used to clean up allocated resources.
~class_name();
Destructors are invoked when an object goes out of scope or a pointer to an object is deleted.
#include <iostream>
class MyClass
{
public:
MyClass() {} // constructor
~MyClass() { // destructor
std::cout << "Destructor invoked.";
}
};
int main()
{
MyClass o;
} // destructor invoked here, when o goes out of scope
62 Copyright © Slobodan Dmitrovic
Operator overloading
Objects of classes can be as used operands in an expression. To use them as operands, we need to
overload the operators for complex types such as classes. We can overload the following operators:
• arithmetic operators
• binary operators
• boolean operators, unary operators
• comparison operators
• compound operators
• function call operators
• subscript operators
+, -, *, /, %, ^, &, |, ~, !=, <, >, ==, !=, <=, >=, +=, -=, *=, /=, %=, ^=, &=, |=,
<<, >>, >>=, <<=, &&, ||, ++, --, ->, *, ->, (), []
Each operator carries its signature and set of rules when overloading for classes. Some operator
overloads are implemented as member functions, some as freestanding functions.
63 Copyright © Slobodan Dmitrovic
Operator overloading
Example of overloading the prefix ++ operator
class MyClass
{
private:
int x;
double d;
public:
MyClass() : x{ 0 }, d{ 0.0 }{}
MyClass& operator++() {
++x;
++d;
return *this;
}
};
int main()
{
MyClass myobject;
++myobject; // prefix operator
[Link]++(); // the same as
}
64 Copyright © Slobodan Dmitrovic
Classes
Inheritance
We can derive a class from an existing class. This approach is known as inheritance.
class derived_class : public base_class {};
It is also said that the derived class is a base class. A simple inheritance example:
class MyBaseClass
{
// base class members / code
};
class MyDerivedClass : public MyBaseClass
{
// derived class members / code
};
Inheritance is one of the building blocks of object-oriented programming.
65 Copyright © Slobodan Dmitrovic
Classes
Inheritance example
Derived class can access protected and public members of the base class. A derived class can also
introduce its own members.
class MyBaseClass class MyDerivedClass : public MyBaseClass
{ {
public: public:
int x; // accessible to all bool b; // introduces its own members
protected: };
double d; // accessible to base class
// and derived class
private:
char c; // accessible to base class
};
An object of the derived class can access only public members.
int main()
{
MyDerivedClass o;
o.x = 123;
o.b = true;
66 Copyright © Slobodan Dmitrovic
}
Classes
Polymorphism
Polymorphism is the ability of the object to take multiple forms, to morph into different types. A pointer to a
derived class is compatible with a pointer to the base class. Together with inheritance and interfaces, this
is used to achieve the functionality known as polymorphism. Polymorphism in C++ is achieved through an
interface known as virtual functions. A virtual function is a function whose behaviour can be overridden in
subsequent derived classes.
Polymorphism step 1 - inheritance
To achieve polymorphic behaviour, first we need to have a base class and a derived class.
class MyBaseClass
{
};
class MyDerivedClass : public MyBaseClass
{
};
67 Copyright © Slobodan Dmitrovic
Classes
Polymorphism step 2 - interfaces
In base class we implement the virtual function whose behaviour we want to override in the derived class.
The signature of the derived class member function must be the same as the base class virtual member
function. Virtual functions can be pure virtual by specifying the = 0;. A class with at least one pure virtual
function is called an abstract class and cannot be instantiated.
class MyBaseClass
{
public:
virtual void dowork() { std::cout << "Hello from a base class." << '\n';}
virtual ~MyBaseClass() {}
};
class MyDerivedClass : public MyBaseClass
{
public:
void dowork() {
std::cout << "Hello from a derived class." << '\n';
}
};
68 Copyright © Slobodan Dmitrovic
Classes
Polymorphism step 2 - interfaces
In base class we implement the virtual function whose behaviour we want to override in the derived class.
The derived class has a function with the same name and same type of arguments as the member
function in the base class. Virtual functions can be pure virtual by specifying the = 0;. A class with at least
one pure virtual function is called an abstract class and cannot be instantiated.
class MyBaseClass
{
public:
virtual void dowork() = 0;
virtual ~MyBaseClass() {}
};
class MyDerivedClass : public MyBaseClass
{
public:
void dowork() {
std::cout << "Hello from a derived class." << '\n';
}
};
69 Copyright © Slobodan Dmitrovic
Classes
Polymorphism step 3 – pointers
Having a pointer to a base class instantiated as a pointer to a derived class allows our object to morph into
appropriate type and through interfaces, invoke the appropriate member function.
#include <iostream>
class MyBaseClass
{
public:
virtual void dowork() { std::cout << "Hello from a base class." << '\n'; }
virtual ~MyBaseClass() {}
};
class MyDerivedClass : public MyBaseClass {
public:
void dowork() { std::cout << "Hello from a derived class." << '\n'; }
};
int main()
{
MyBaseClass* p = new MyDerivedClass;
p->dowork(); // output: Hello from a derived class.
delete p;
} 70 Copyright © Slobodan Dmitrovic
The static specifier
The static specifier controls the storage duration and linkage.
The static object declaration
When used in local variable declaration, it specifies When used in global scope variable declaration, it
static storage duration. specifies internal linkage.
void myFunction() { static int x;
static int x = 0; // x has static // the same as:
// storage duration namespace {
x++; int x;
} }
The static class member
Declares class members that are not part of / bound to an object.
class MyClass class MyClass
{ {
public: public:
static int x; // declaration static void myFunction(); // declaration
}; };
// definition // definition
int MyClass::x = 123; void MyClass::myFunction() {function_code};
71 Copyright © Slobodan Dmitrovic
Smart pointers
Smart pointers are pointers that own the object they point to and automatically destroy the object and
deallocate the memory once they go out of scope. Smart pointers are declared inside a <memory> header.
Unique pointer
A unique pointer std::unique_ptr is a pointer that owns an object it points to. The pointer can not be copied.
Once it goes out of scope, the unique pointer deletes the object and deallocates the memory.
#include <iostream>
#include <memory>
int main()
{
std::unique_ptr<int> up(new int{ 123 });
std::cout << *up;
}
Prefer initializing unique pointers through a std::make_unique function.
std::unique_ptr<int> up = std::make_unique<int>(123);
std::unique_ptr<double> up2 = std::make_unique<double>(456.789);
std::unique_ptr<MyClass> up3 = std::make_unique<MyClass>(arguments);
83 Copyright © Slobodan Dmitrovic