Download as pdf or txt
Download as pdf or txt
You are on page 1of 80

C++

Nilesh Pabuwal
Index
• Chapter 1, Your first C++ Application, will equip you with the fundamental tools and techniques required to get started building basic C++
applications.
• Chapter 2, Built-in Data Types, vectors and arrays. These are then utilized in the creation of a real-world sign-up application.
• Chapter 3, Control Flow
• Chapter 4, Operators, presents a variety of operators provided by C++, describing what they do and how they can allow us to manipulate our
data.
• Chapter 5, Pointers and References
• Chapter 6, Dynamic Variables, introduces dynamic variables ,their ownership and Lifetime – that is, variables that can be created when needed
and can hold an arbitrarily large amount of data that is limited only by the memory that is available.
• Chapter 7, Classes and Structs, presents the fundamentals of structs and classes.
• Chapter 8, Object-Oriented Principles, presents best practices for designing classes and will give you an overview of abstraction and
encapsulation, where to use them.
• Chapter 9, Advanced Object-Oriented Principles, presents a number of advanced object-oriented principles, including inheritance and
polymorphism, that will allow us to build more dynamic and powerful C++ applications.
• Chapter 10, Templates, covers an overview of templates and gives some examples of how they can be used.
• Chapter 11, Containers and Iterators.
• Chapter 12, Exception Handling

In parallel – Students would be working on Real-Time case based on their family business and try to convert and create Project.
Chapter 1, Your first C++ Application, will equip you
with the fundamental tools and techniques required
to get started building basic C++ applications.
Why C++ , Advantages
• Performance: By putting the programmer close to the hardware, C++ allows us to write
very efficient programs. Along with low-level memory access, the abstraction between
code and what the machine will do is smaller than in most other languages, meaning
you can manipulate the system better.
• Portability: C++ can be cross-compiled to a wide array of platforms, and runs on
everything from watches to televisions. If you're writing an application or library for
more than one platform.
• General purpose: C++ is a general-purpose programming language, and is used in
everything from video games to enterprise. With a rich feature set spanning everything
from direct memory management to classes and other Object-Oriented Programming
(OOP) principles, you can make C++ work for you.
• Large libraries: Since the language is used in so many applications, there's an
abundance of libraries to choose from. With hundreds of open source repositories, the
wealth of information (and the support systems that come with it) is vast.
Online Editors
• Tutorialspoint C++ compiler: https://www.tutorialspoint.com/compile_cpp_online.php.
• cpp.sh: This website allows you to pick a C++ language version and warning level, and compile a
single file. However, it does not print error messages from the operating system. You can find it
at http://cpp.sh/.
• godbolt compiler explorer: This website allows you to compile a single file on many different
compilers and shows the output assembly language; its UI is a little subtle for some tastes. It
prints error messages from the operating system. You can find it at https://godbolt.org/.
• coliru: This website allows you to compile a single file. It prints error messages from the operating
system. You can find it at http://coliru.stacked-crooked.com/.
• repl.it: This website allows you to compile multiple files. You can find it
at https://repl.it/languages/cpp.
• Rextester: This website lets you compile a single file using Microsoft Visual C++. You can find it
at https://rextester.com/.
• Visual Studio Editor
C++ Build Pipeline
#include <iostream>
int main()
{
std::cout << "Hello World!";
return 0;
}
Anatomy of a C++ Application
• Starting from the top, we have a preprocessor directive:
#include <iostream>
• Preprocessor directives are statements that allow us to perform
certain operations before the program is built.
• The include directive is a very common directive that you'll see in
most C++ files, and it means "copy here." So, in this case, we're going
to copy the contents of the iostream header file into our application,
and in doing so, allow ourselves to use input/output functionality it
provides.
Anatomy of a C++ Application
• Next, we have our entry point, main():
int main()

The main() function is where your C++ application will kick-off. All applications will have this function defined
and it marks the start of our application—the first code that will be run. This is typically your outer-most loop
because as soon as the code in this function is complete, your application will close.

• Next, we have an IO statement that will output some text to the console:
std::cout << "Hello World!";

Because we have included the iostream header at the start of our application, we have access to various input
and output functionality. In this case, std::cout. cout allows us to send text to the console, so when we run our
application, we see that the text "Hello World!" is printed. We'll cover data types in more detail in the coming
chapters.

• Finally, we have a return statement:


return 0;
Chapter 2, Built-in Data Types, vectors and
arrays. These are then utilized in the creation
of a real-world sign-up application
Type Modifiers
•signed: The signed keyword specifies that our variable can hold both positive and negative values. This increases the
maximum lower value since we can now go negative, but doing so decreases the maximum upper value. This is because
the range of values the variable can hold doesn't change; it just shifts, meaning half the range is now dedicated to negative
numbers.

•unsigned: The unsigned keyword specifies that our variable should only hold positive values. This increases the upper
range of the variable but decreases its lower range as it's capped at 0.

•long: The long keyword ensures that our variable will be at least the size of an int; typically, this will be 4 bytes. This will,
in some cases, increase the range of the value that can be stored.

•long long (C++11): The long long keyword, added in C++11, ensures that our variable will be greater in size than long;
typically, this will be 8 bytes. This will, in most cases, increase the range of the value that can be stored.

•short: The short keyword ensures that our variable has the smallest memory footprint it can, whilst ensuring a size less
than long; typically, this will be 4 bytes.

Note
The exact size of data types depends on factors such as the architecture that you're working with and what compiler flags are set, though
typical sizes will be shown in a reference chart shortly. It's important to note that the C++ standard does not guarantee absolute sizes for
types but minimum ranges that they must be able to store. This then means that modified types may also differ between platforms.
Built-In Types
•bool: The bool type stores either a true (non-zero) or false (0) value and has
a size of one byte.

•int: The int type is used to store integers and is typically four bytes in size.

•char: The char type is used to store a single character. This is stored in the
form of an integer and gets resolved into a character depending on which
character set is used, typically ASCII. This data type is one byte in size.

•float: The float type represents single-precision floating-point numbers and


is typically 4 bytes in size.

•double: The double type represents double-precision floating-point


numbers and is typically 8 bytes in size.

•void: The void type is a special type that denotes an empty value. You
cannot create objects of the void type. However, it can be used by pointers
and functions to denote an empty value—for example, a void pointer that
points to nothing, or a void function that doesn't return anything.

•wide character: The wchar_t type is used to store wide characters (Unicode
UTF-16). The size of wchar_t is compiler-specific, although C++11 introduced
the fixed size types, char16_t and char32_t.
Inputs From Keyboard For different Data Types
#include <iostream>
using namespace std;
#include <iostream>
#include <string> int main() {
using namespace std; char *p = new char[1024]; // allocate memory
cin >> p; //forexample: haha
int main() char* q = p;
{ cout << "&q = " << &q << endl;
string name; cout << "q = " << q << endl;
cout << "Enter your name: "; return 0;
cin>>name; }
getline(cin, name); // To read a line with spaces
cout << name; #include<iostream>
return 0; using namespace std;
} int main()
{
char myChar = 'a’;
int ASCII = myChar;
for(int i=0;i<255;i++)
{
cout<<char(i)<<i<<'\t’;
}
return 0;
}
Declaring Variable and Checking its Size
#include<iostream>
using namespace std;
int main()
{
int myInt = 1;
bool myBool = false;
char myChar = 'a’;
float myfloat=3.4;
std::cout << "The size of an int is " << sizeof(myInt) << ".\n";
std::cout << "The size of a bool is " << sizeof(myBool) << ".\n";
std::cout << "The size of a char is " << sizeof(myChar) << ".\n";
std::cout << "The size of a char is " << sizeof(myfloat) << ".\n";

return 0;
}
Converting Values from int, float, string
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <cstdlib> // for atoi function #include <sstream> // for stringstream
using namespace std; using namespace std;

int main() { int main() {


string str = "12345"; int num = 12345; // 123.45 (Float)
int num = atoi(str.c_str()); stringstream ss;
cout << "Converted integer: " << num << endl; ss << num;
return 0; string str = ss.str();
} cout << "Converted string: " << str << endl;
return 0;
#include <iostream> }
#include <string>
using namespace std;

int main() {
string str = "123.456";
float fnum = stof(str);
cout << "Converted float: " << fnum << endl;
return 0;
}
Containers - Array
Multidimensional - Array

int myArray[3][5]; int myArray[3][5] { {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5} };


Syntex
//Option 1 Without Initialization //How Many Element it Contains
int customerAges[5]; sizeof(customerAges)/sizeof(customerAges[0])
std::cout << customerAges[0] << std::endl;
std::cout << customerAges[1] << std::endl; std::array<int, 5> myArray {1, 2, 3, 4, 5};
std::cout << customerAges[2] << std::endl; std::cout << std::size(myArray) << std::endl;
std::cout << customerAges[3] << std::endl; int myArray[5] = {1, 2, 3, 4, 5};
std::cout << customerAges[4] << std::endl; std::cout << std::size(myArray) << std::endl;

// Option 2 – Wit Initialization


int customerAges[5] = {1, 2, 3, 4, 5};
//Check MEMORY Locations
//Option 3
int customerAges[] = {1, 2, 3, 4, 5}; int customerAges[] = {1, 2, 3, 4, 5};
std::cout << &customerAges[0] << std::endl;
//Option 4 std::cout << &customerAges[1] << std::endl;
int customerAges[5] = {1, 2, 3}; std::cout << &customerAges[2] << std::endl;
std::cout << &customerAges[3] << std::endl;
//Option 5 std::cout << &customerAges[4] << std::endl;
int customerAges[5] = {};
Sample Program
//BLOCK 1 //BLOCK 2 #include <iostream>
bool bIsRunning = true;
// Arrays exercise. while (bIsRunning)
using namespace std;
#include <iostream> {
#include <string> int userIndex = 0; int main() {
#define NAME_COUNT 5 std::string inputString = ""; int arr[5];
int main() std::cout << "Enter user-id of user to fetch or -1 to quit: ";
{ std::getline(std::cin, inputString);
std::string names[NAME_COUNT][2]; userIndex = std::stoi(inputString); cout << "Enter 5 integers: ";
std::cout << "Please input usernames." << std::endl; if (userIndex == -1) for (int i = 0; i < 5; i++) {
for (int i = 0; i < NAME_COUNT; ++i) {
{ bIsRunning = false;
cin >> arr[i];
std::cout << "User " << i + 1 << " Forename: "; } }
std::getline(std::cin, names[i][0]); else
std::cout << "User " << i + 1 << " Surname: "; { cout << "You entered: ";
std::getline(std::cin, names[i][1]); if (userIndex >= 0 && userIndex < NAME_COUNT)
} { for (int i = 0; i < 5; i++) {
std::cout << "User " << userIndex << " = "<< cout << arr[i] << " ";
names[userIndex] << std::endl; }
}
else
cout << endl;
{
std::cout << "Invalid user index" << std::endl; return 0;
} }
}
}
}
Vectors: Vectors are similar to arrays in that they store collections of elements continuously in memory,
but vectors have dynamic sizes. This means that we don't need to know their size at compile time; we can just
define a vector and add/remove elements at will. Given this, they manage their size carefully.
Declaring
// Vector example.
std::vector<int> myVector; #include <iostream>
#include <string>
std::vector<int> myVector(myArray, myArray + myArraySize);
#include <vector>
std::vector<int> myVector(myVector2.begin(), myVector2.end());
std::vector < int > myVector;
Accessing Elements void PrintVector()
int myFirstElement = myVector[0]; {
int mySecondElement = myVector[1]; for (int i = 0; i < myVector.size(); ++i)
{
OR std::cout << myVector[i];
int myFirstElement = myVector.at(0); }
int mySecondElement = myVector.at(1); std::cout << "\n\n";
}
Initialization
int main()
std::vector<int> myVector {1, 2, 3, 4, 5}; {
PrintVector();
std::vector<int> myVector(3, 1); }
The following initialization will give us a vector with three elements, all with a value of 1:
// Declaration and Initialization: //Iterating Through Elements:
#include <vector> for (int i = 0; i < myVector.size(); ++i) {
using namespace std; cout << myVector[i] << " ";
// Declaration of an empty vector of integers }
vector<int> myVector; // or using range-based for loop
// Initialization with values for (const auto& element : myVector) {
vector<string> fruits = {"Apple", "Orange", "Banana"}; cout << element << " ";
}
// Adding Elements
// Add an element at the end // Remove all elements, making the vector empty
myVector.push_back(42); myVector.clear();
// Insert an element at a specific position
// Sort the elements in ascending order
myVector.insert(myVector.begin() + 1, 99);
sort(myVector.begin(), myVector.end());
// Access an element using subscript operator
int value = myVector[0]; // Find the iterator for a specific value
// Access an element using the at() method auto it = find(myVector.begin(), myVector.end(), 42);
int anotherValue = myVector.at(2); if (it != myVector.end()) {
// Element found
myVector.pop_back(); // Remove the last element }
// Remove an element at a specific position
myVector.erase(myVector.begin() + 1); auto is a keyword introduced in C++11 to enable automatic type inference.
It allows the compiler to automatically deduce the type of a variable based
int size = myVector.size(); // number of elements on its initializer or return type of a function. This feature is particularly
int capacity = myVector.capacity(); // current storage useful when dealing with complex or templated types, making the code
more concise and easier to maintain
#include <iostream> There are other containers available, such as stacks, trees, and
#include <vector> linked lists
#include <algorithm>
int main() { #include <iostream>
// Create a vector of integers #include <vector>
std::vector<int> numbers = {1, 2, 3, 4, 5};
// Element to find int main() {
int target = 3; // Create a vector
// Use auto to deduce the iterator type std::vector<int> numbers = {1, 2, 3, 4, 5};
auto result = std::find(numbers.begin(), numbers.end(),
target); // Create a pointer to the vector
// Check if the element was found std::vector<int>* ptrToVector = &numbers;
if (result != numbers.end()) { // Access elements using the pointer
std::cout << "Element " << target << " found at index: " for (const auto& num : *ptrToVector) {
<< std::distance(numbers.begin(), result) << std::endl; std::cout << num << " ";
} else { }
std::cout << "Element " << target << " not found in the std::cout << std::endl;
vector." << std::endl; return 0;
} }

Why const auto&: ?


return 0;
•const: Ensures that the elements are not modified.
}
•auto: Allows the compiler to deduce the type of elements.
•&: Represents a reference to the elements, avoiding
unnecessary copies
Struct
Structs are very similar to classes. The difference between the two is that, by default, class members are private, and in a
struct, they are public. Because of this, we tend to use structs to define objects whose purpose is mainly to store data.

// Struct example.
#include <iostream>
#include <string>
struct Coordinate
{
float x = 0;
float y = 0;
};
int main()
{
Coordinate myCoordinate;
myCoordinate.x = 1;
myCoordinate.y = 2;
std::cout << "Coordinate: " << myCoordinate.x << ", " << myCoordinate.y;
}
•Classes and structs encapsulate variables and behaviors.
Classes •Class members are private by default, whereas they're
public in a struct.
A class is a collection of variables and functionality, encapsulated neatly
•We can modify the visibility of our members with access
within a single object. When we define a class, we're creating a
modifiers.
blueprint for that object. This means that every time we want to create •Constructors and destructors can be used to call code at
an object of that type, we use that blueprint to construct our object. each end of an object's lifetime.
// Class example. Members (variables and functions) declared in a C++ class are,
#include <iostream>
#include <string>
by default, private. This means that they're only accessible to
class MyClass the class itself, so cannot be accessed by external classes. This
{ can be changed, however, through the use of access modifiers;
private: // Any members declared from this point forth will be private. we'll cover these shortly. Classes can also inherit from one
int myInt = 0;
public: another,
void IncrementInt()
{ •Public—Any members declared public are accessible from
myInt++; anywhere the class is.
std::cout << "MyClass::IncrementInt: " << myInt;
};
•Private—Any members declared private are only available to the
protected:// Any members declared from this point forth will be protected. class in which they're defined and to friend functions.
•Protected—Protected members are similar to private members,
}; with the addition that child classes can access them.
int main()
{ Note
MyClass classObject; Child classes are those that inherit from a base class. This will be
classObject.IncrementInt(); covered in detail in Chapter 10, Advanced Object-Oriented
}
Principles.
Exercise
// Accessibility example. #include <iostream>
#include <iostream> #include <string>
#include <string> class MyClass
class MyClass {
{ public:
public: MyClass()
int myPublicInt = 0; {
protected: std::cout << "My Class Constructor Called\n";
int myProtectedInt = 0; myPublicInt = 5;
private: }
int myPrivateInt = 0; ~MyClass()
}; {
std::cout << "My Class Destructor Called\n";
int main() }
{ int myPublicInt = 0;
MyClass testClass; };
std::cout << testClass.myPublicInt << "\n"; int main()
std::cout << testClass.myProtectedInt << "\n"; {
std::cout << testClass.myPrivateInt << "\n"; std::cout << "Application started\n";
} MyClass testClass;
std::cout << testClass.myPublicInt << "\n";
// Classes/struct exercise. int main()
#include <iostream> {
#include <string> MyClass classObject;
class MyClass
{ std::cout << "classObject::myInt: " << classObject.myInt << "\n";
public: std::cout << "classObject::myBool: " << classObject.myBool << "\n";
int myInt = 0; std::cout << "classObject::GetString: " << classObject.GetString() << "\n";
bool myBool = false;
std::string GetString() MyStruct structObject;
{
return "Hello World!"; std::cout << "\nstructObject::myInt: " << structObject.myInt << "\n";
} std::cout << "structObject::myBool: " << structObject.myBool << "\n";
}; std::cout << "structbject::GetString: " << structObject.GetString() << "\n";
struct MyStruct }
{
int myInt = 0;
int myBool = 0;
std::string GetString()
{
return "Hello World!";
}
};
Storage Life time
#include <iostream> #include <iostream> // Static example.
void MyFunc() #include <string> #include <iostream>
{ int MyInt() #include <string>
int myInt1 = 1; { int MyInt()
} int myInt = 0; {
int main() return ++myInt; static int myInt = 0;
{ } return ++myInt;
int myInt2 = 2; int main() }
{ { int main()
int myInt3 = 3; for (int i = 0; i < 5; ++i) {
} { for (int i = 0; i < 5; ++i)
// print values std::cout << MyInt(); {
std::cout << myInt1 << std::endl; } std::cout << MyInt();
std::cout << myInt2 << std::endl; } }
std::cout << myInt3 << std::endl; }
}
switch (std::stoi(inputString))

Practical Exercise {
case 1:
{
// Activity 3: SignUp Application. int main() std::string name = "";
#include <iostream> { int age = 0;
std::cout << "User SignUp Application\n" << std::endl; std::cout << "\nAdd User. Please enter user name and age:\n";
#include <string> std::cout << "Name: ";
bool bIsRunning = true;
#include <vector> while (bIsRunning)
std::getline(std::cin, name);
std::cout << "Age: ";
#include <stdexcept> { std::getline(std::cin, inputString);
struct Person std::cout << "Please select an option:\n"; age = std::stoi(inputString);
{ std::cout << "1: Add Record\n"; AddRecord(name, age);
}
int age = 0; std::cout << "2: Fetch Record\n";
break;
std::cout << "3: Quit\n\n";
std::string name = ""; case 2:
std::cout << "Enter option: "; {
}; std::string inputString; int userID = 0;
std::vector<Person> records; std::getline(std::cin, inputString); std::cout << "\nPlease enter user ID:\n";
void AddRecord(std::string newName, int std::cout << "User ID: ";
//Determine user selection.
std::getline(std::cin, inputString);
newAge) userID = std::stoi(inputString);
{ Person person;
try
Person newRecord; {
newRecord.name = newName; person = FetchRecord(userID);
newRecord.age = newAge; }
catch (const std::out_of_range& oor)
records.push_back(newRecord); {
std::cout << "\nUser record added std::cout << "\nError: Invalid UserID.\n\n";
break;
successfully.\n\n"; }
}; std::cout << "User Name: " << person.name << "\n";
Person FetchRecord(int userID) std::cout << "User Age: " << person.age << "\n\n";
}
{ break;
return records.at(userID); case 3:
bIsRunning = false;
}; break;
default:
std::cout << "\n\nError: Invalid option selection.\n\n";
break;
}
} }
Chapter 3: Control Flow
If – Else – Syntex
if (condition) { //Chained if-else (using else if)
// Code to execute if condition is true if (condition1) {
} // Code to execute if condition1 is true
} else if (condition2) {
if (condition) { // Code to execute if condition1 is false and condition2 is true
// Code to execute if condition is true } else {
} else { // Code to execute if both conditions are false
// Code to execute if condition is false }
}
//else if - Multiple Conditions
//Nested if – Else if (condition1 && condition2) {
if (condition1) { // Code to execute if both condition1 and condition2 are true
if (condition2) { } else if (condition3 || condition4) {
// Code to execute if both conditions are true // Code to execute if either condition3 is true or condition4 is
} else { true
// Code to execute if condition2 is false } else {
} // Code to execute if none of the above conditions are true
} else { }
// Code to execute if condition1 is false
} //Ternary Operator:
variable = (condition) ? expression1 : expression2;
Switch Case
switch (expression) { //Multiple Case
case value1: switch (expression) {
// Code to execute if expression equals value1 case value1:
break; case value2:
case value2: // Code to execute if expression equals either value1 or
// Code to execute if expression equals value2 value2
break; break;
// ... additional cases // ... additional cases
default: }
// Code to execute if expression doesn't match any case
} // No break means control will fall through behaviour
switch (expression) {
//Switch with Initialization case value1:
switch (int var = some_function(); var) { // Code for value1
case 1: break;
// ... case value2:
break; // Code for value2
// ... other cases case value3:
} // Code for value3 (will execute if value2 is matched)
break;
// ... additional cases
}
//Enumeration in Switch
//Test for Ternary Conditional Operation
int a = 5;
enum Days { MON, TUE, WED, THU, FRI, SAT, SUN };
int b = 10;
int max = (a > b) ? a : b;
Days today = MON;
switch (today) {
case MON: #include<iostream>
// ... #include<string>
break; using namespace std;
// ... other cases int main()
} {

//Using Switch Without Expression int x[] ={1,2,3};


int i = 1; for(int i:x)
switch (i) { {
case 1: cout<<i<<"\t";
// ... }
break;
// ... other cases for(int i=0; i<(sizeof(x)/sizeof(x[0]));i++)
} {
cout<<x[i]<<"\t";
}
return 0;
}
for (int i = 0; i < 10; ++i) {
For Loop if (i == 5) {
continue; // Skip the iteration when i is 5
}
if (i == 8) {
break; // Exit the loop when i is 8
}
for (initialization; condition; update) { // Code to execute
// Code to execute }
}
//For Loop with Declared Variable
for (;;) { for (int i = 0; i < 5; ++i) {
// Code to execute indefinitely int j = i * 2;
} // j is only accessible within this for loop
//Range based For Loop Version - C++11 }
int arr[] = {1, 2, 3, 4, 5}; // j is not accessible here
for (int num : arr) {
// Code to execute for each element in arr //Nested For Loop
} for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j) {
//For Loop with Multiple Initialization Updates // Code to execute for each combination of i and j
for (int i = 0, j = 10; i < 5; ++i, --j) { }
// Code to execute }
}
Do-While //Single Line Do-While
do std::cout << "Hello, World!" << std::endl; while (false);

#include <iostream> //Nested Do-While


int main() { int i = 0;
int count = 0; do {
int j = 0;
do { do {
std::cout << "Count: " << count << std::endl; std::cout << i << "," << j << std::endl;
count++; j++;
} while (count < 5); } while (j < 3);
i++;
return 0; } while (i < 2);
}
//Continue
int i = 0;
//Break
do {
int i = 0;
if (i == 2) {
do {
i++;
std::cout << i << std::endl;
continue;
if (i == 3) break;
}
i++;
std::cout << i << std::endl;
} while (true);
i++;
} while (i < 5);
While Loop //Single Line
int i = 0;
while (i < 5) std::cout << i++ << " ";
while (condition) {
// code block to execute //break
}
int i = 0;
//Nested while (true) {
int i = 0; std::cout << i << std::endl;
while (i < 3) { if (i == 3) break;
int j = 0; i++;
while (j < 2) { }
std::cout << i << "," << j << std::endl;
j++; //Continue
} int i = 0;
i++; while (i < 5) {
} if (i == 2) {
i++;
continue;
}
std::cout << i << std::endl;
i++;
}
GoTo #include <iostream>

int main() {
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
std::cout << "(" << i << ", " << j << ") ";

// If certain condition is met, exit both loops using goto


if (i == 3 && j == 5) {
goto exitLoop;
}
}
std::cout << std::endl;
}

// This is the label we jump to


exitLoop:
std::cout << "\nExited the loop using goto!\n";

return 0;
}
Chapter 4: Operators, presents a variety of
operators provided by C++, describing what they do
and how they can allow us to manipulate our data.
Arithmetic Operators
// Arithmetic operators. // Prime number checker.
#include <iostream> #include <iostream>
#include <string>
#include <string> int main()
int main() {
{ int numberToCheck = 0;
std::cout << "Prime number checker\n";
int addition = 3 + 4;
std::cout << "Enter the number you want to check: ";
int subtraction = 5 - 2; std::cin >> numberToCheck;
int division = 8 / 4; if (numberToCheck <= 1)
int multiplication = 3 * 4; {
std::cout << numberToCheck << " is not prime.";
std::cout << addition << "\n"; return 0;
std::cout << subtraction << "\n"; }
std::cout << division << "\n"; else if (numberToCheck == 2)
{
std::cout << multiplication << "\n";
std::cout << numberToCheck << " is prime.";
} return 0;
}
// Arithmetic operators – Modulus for (int i = 2; i < numberToCheck; ++i)
#include <iostream> {
#include <string> if (numberToCheck % i == 0)
{
int main() std::cout << numberToCheck << " is not prime.";
{ return 0;
int modulus = 11 % 2; }
std::cout << modulus << "\n"; }
std::cout << numberToCheck << " is prime.";
} }
Relational Operators //Block 2
if (time < 0000 || time > 2400)
{
std::cout << "Invalid time.";
return 0;
}
if (time == 0000)
{
//Block 1
std::cout << "It's currently midnight.";
// Time of Day Calculator. }
#include <iostream> else if (time == 1200)
#include <string> {
std::cout << "It's currently noon.";
int main() }
{ else if (time >= 0600 && time < 1200)
std::cout << "***Time of Day Calculator***\n"; {
std::cout << "It's currently morning.";
std::cout << "Enter time in military format. eg. (1800, 1430)\n\n";
}
std::cout << "Enter time: "; else if (time > 1200 && time <= 1700)
std::string input; {
getline(std::cin, input); std::cout << "It's currently afternoon.";
}
int time = std::stoi(input); else if (time > 1700 && time <= 2000)
{
std::cout << "It's currently evening.";
}
else if (time > 2000 || time < 0600)
{
std::cout << "It's currently night.";
}
}
Unary Operators
// Increment/Decrement example. So far, the operators that we've used had a value, typically called an operand, on
#include <iostream> either side of them: rhs and lhs. Unary operators are those operators, however, that
#include <string> take only one value and modify that. We'll be taking a quick look at minus (-),
int main() increment (++), and decrement (--). There are a number of other unary operators
{ (logical complement (!) and bitwise complement (~))
int myInt = 1;
std::cout << ++myInt << std::endl; // Pre/Post Increment Example.
std::cout << --myInt << std::endl; #include <iostream>
} #include <string>
int main()
// Negation example. {
#include <iostream> int myInt = 5;
#include <string> std::cout << ++myInt << std::endl;
int main() std::cout << myInt << std::endl;
{ myInt = 5;
int myInt = -1; std::cout << myInt++ << std::endl;
std::cout << -myInt * 5 << std::endl; std::cout << myInt << std::endl;
myInt = 1; }
std::cout << -myInt * 5 << std::endl;
}
Assignment Operators
// Assignment Operators Example.
#include <iostream>
#include <string>
int main()
{
int myInt = 5;
myInt += 5;
std::cout << myInt << std::endl;
myInt -= 5;
std::cout << myInt << std::endl;
myInt *= 5;
std::cout << myInt << std::endl;
myInt /= 5;
std::cout << myInt << std::endl;
myInt %= 5;
std::cout << myInt << std::endl;
}
Logical Operators
•AND (&&): This returns true when both conditions are true, and false otherwise.
•OR (||): This returns true when either condition is true, and false otherwise.
•NOT (!): This returns true if the condition is false, and true otherwise; essentially, it returns the opposite of the
condition.

// Logical Operators Exercise. // Check if all or any of the names match.


#include <iostream> if (name1 == name2 && name2 == name3)
#include <string> {
int main() std::cout << "\nAll the names are the same.";
{ }
std::string name1; else if (name1 == name2 || name2 == name3 || name1 ==
std::string name2; name3)
std::string name3; {
std::cout << "Please enter name 1: "; std::cout << "\nSome of the names matched.";
std::cin >> name1; }
std::cout << "Please enter name 2: "; // Check if names 1 and 2 are different.
std::cin >> name2; std::cout << "\nNames 1 and 2 are " << (!(name1 == name2) ?
std::cout << "Please enter name 3: "; "different." : "the same.") << std::endl;
std::cin >> name3; }
Operator Overloading returnType operator symbol (arguments)
// Operator Overloading class Point {
#include <iostream> private:
#include <string> int x, y;
class Person public:
{ Point(int x = 0, int y = 0) : x(x), y(y) {}
public:
Person(int age, std::string name): age(age), name(name) {}; Point operator+(const Point& p) {
float age = 0; Point sum;
std::string name = ""; sum.x = x + p.x;
bool operator == (Person const & other) sum.y = y + p.y;
{ return sum;
return ((age == other.age) && (name == other.name)); }
} void display() {
}; std::cout << "x: " << x << ", y: " << y << std::endl;
int main() }
{ };
Person PersonA = Person(27, "Lucy"); int main() {
Person PersonB = Person(27, "Lucy"); Point p1(2, 3), p2(1, 1), p3;
Person PersonC = Person(27, "Susan"); p3 = p1 + p2; // Using overloaded +
std::cout << (PersonA == PersonB) << std::endl; p3.display();
std::cout << (PersonB == PersonC) << std::endl; return 0;
} }
Overloading the << Operator for a Custom Class

class Point {
private:
int x, y;

public:
Point(int x = 0, int y = 0) : x(x), y(y) {}

friend std::ostream& operator<<(std::ostream& os, const Point& p)


{
os << "x: " << p.x << ", y: " << p.y;
return os;
}
};

int main() {
Point p(2, 3);
std::cout << p << std::endl; // Using overloaded <<
return 0;
}
Overloading the = Operator for a Custom Class

class Point {
private:
int x, y;

public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
Point& operator=(const Point& p) {
x = p.x;
y = p.y;
return *this;
}
void display() {
std::cout << "x: " << x << ", y: " << y << std::endl;
}
};

int main() {
Point p1(2, 3), p2;
p2 = p1; // Using overloaded =
p2.display();
return 0;
}
Bitwise AND (&): Takes two numbers as operands and Left Shift (<<): Shifts the bits of the number to the left by the
does AND on every bit of two numbers. specified number of positions.
int a = 5; // 0101 in binary
int a = 5; // 0101 in binary
int b = 3; // 0011 in binary
int result = a << 2; // 10100 in binary, which is 20 in decimal
int result = a & b; // 0001 in binary, which is 1 in decimal
Right Shift (>>): Shifts the bits of the number to the right by
Bitwise OR (|): Takes two numbers as operands and does
the specified number of positions.
OR on every bit of two numbers.
int a = 5; // 0101 in binary int a = 20; // 10100 in binary
int b = 3; // 0011 in binary int result = a >> 2; // 00101 in binary, which is 5 in decimal
int result = a | b; // 0111 in binary, which is 7 in decimal

Bitwise XOR (^): Takes two numbers as operands and


does XOR on every bit of two numbers.
int a = 5; // 0101 in binary
int b = 3; // 0011 in binary
Bitwise Operators
int result = a ^ b; // 0110 in binary, which is 6 in decimal
Bitwise NOT (~): Takes one number and inverts all the bits
C++ provides us with six bitwise operators, as follows:
of it.
int a = 5; // 0101 in binary
int result = ~a; // 1010 in binary, which is -6 in decimal
due to two's complement representation
int *pi = &i;

Chapter 5, Pointers and References


Pointers and references are also useful because a pointer to a big array or class instance can be passed into a function,
instead of copying the array or instance into the function's formal argument.
Pointers to all Data Types
int x = 10; float y = 10.5; double z = 20.5; char ch = 'A'; bool flag = true;
int *ptrInt = &x; float *ptrFloat = &y; double *ptrDouble = &z; char *ptrChar = &ch; bool *ptrBool = &flag;

int arr[5] = {1, 2, 3, 4, 5}; class MyClass {


int *ptrArr = arr; // Points to the first element of the array public:
void display() {
int arr[5] = {1, 2, 3, 4, 5}; std::cout << "Inside MyClass" << std::endl;
int (*ptr)[5] = &arr; // Pointer to an array of 5 integers }
};
void func(int a) {
std::cout << "Value: " << a << std::endl; void (MyClass::*ptrMemberFunc)() = &MyClass::display;
}

void (*ptrFunc)(int) = &func;

void *ptrVoid;
int a = 10;
ptrVoid = &a; // Can point to any data type but requires explicit
typecasting before dereferencing
References
#include <iostream> #include <iostream> int arr[5];
using namespace std; using namespace std; int (&refToArray)[5] = arr;
int main() void copychars(char* from, char* to, int count)
{ { struct MyStruct {
int i = 10; if (from == nullptr || to == nullptr) int x;
int & ir = i; return; float y;
i = i + 10; while (count-- > 0) };
ir = ir * 10; { MyStruct s;
cout << "i = " << i << endl; *to++ = *from++; MyStruct& refToStruct = s;
int *ip = & ir; }
class MyClass {
*ip = 33; }
// ...
cout << "i = " << i << ", *ip = " << * ip int main()
};
<< ", ir = " << ir << endl; {
MyClass obj;
return 0; char string[] { "uvwxyz" };
MyClass& refToObj = obj;
} char buffer[10];
copychars (string, buffer, 7); int* ptr = nullptr;
Bad References int main()
cout << buffer << endl; int*& refToPtr = ptr;
{
return 0;
char* p = nullptr;
} template <typename T>
char& r = *p;
void function(T& ref) {
r = '!';
enum Color { RED, GREEN, BLUE }; // ...
return 0;
Color& refToColor = RED; }
}
Difference between Pointer and Reference
Heads Pointers References
Declaration and Initialization int* ptr = &variable; int& ref = variable;
You need to explicitly use the * operator for Once initialized, it behaves like an alias to the variable it
dereferencing and the & operator to get the references, and you use it directly.
address.
Memory Address vs. Alias Contains the memory address of another Does not have its own memory address. It's simply another
variable. This means that pointers can be nullptr name for an existing variable. Therefore, you cannot have a
(or NULL in older versions) if they don't point to nullptr reference; a reference must always refer to a valid
any valid memory location. object.
Dereferencing int value = *ptr; ref = 10; // This modifies the original variable.
To access the value of the variable it points to, You directly use the reference name to access or modify the
you use the * operator. value of the referred variable.
Reassignment int anotherVariable = 20; int anotherVariable = 20;
ptr = &anotherVariable; ref = anotherVariable;
// Now ptr points to anotherVariable. // This assigns the value, doesn't change the reference itself.
Nullability Can be set to nullptr to indicate that it doesn't Always refers to a valid object and cannot be nullptr
point to any valid memory location
Deleting //Dynamic Allocation with new and int* ptr = nullptr; Dynamic Allocation with new[] and
delete delete ptr; delete[] (for arrays):
int* ptr = new int; // No effect, safe to delete int* arr = new int[10];
delete ptr; delete[] arr;
Pointers
#include <iostream>
using namespace std;
int main()
{
int i = 12345;
int *p = &i;
cout << "p = " << p << ", &i = " << &i << endl;
cout << "i = " << i << endl;
*p = *p + 2;
cout << "i = " << i << endl;
return 0; //Dereferencing nullptr
} #include <iostream>
using namespace std;
int main()
{
int *p1 = nullptr;
cout << "p1 = " << p1 << endl;
*p1 = 22;
return 0;
}
Dynamic Memory Allocations
int main() { int main() {
int *arr = new int[5]; int a = 10, b = 20, c = 30;
// Dynamically allocate memory for an array of 5 integers int *ptrArr[3] = {&a, &b, &c}; // Array of pointers

for (int i = 0; i < 5; ++i) { for (int i = 0; i < 3; ++i) {


arr[i] = i; // Initialize array std::cout << *ptrArr[i] << " ";
} }

for (int i = 0; i < 5; ++i) { return 0;


std::cout << arr[i] << " "; }
}

delete[] arr; // Deallocate memory


return 0;
}
Pointer to Pointer (Double Pointer):
int main() {
int x = 10;
int *ptr1 = &x;
int **ptr2 = &ptr1; // Pointer to pointer

std::cout << "Value of x: " << x << std::endl;


std::cout << "Value at ptr1: " << *ptr1 << std::endl;
std::cout << "Value at ptr2: " << **ptr2 << std::endl;

return 0;
}
#include <iostream>

Pointers and Functions // Define a function that matches the signature of our function
pointer
void printMessage(const char* message) {
void modifyValue(int *ptr) { std::cout << "Message from function: " << message <<
*ptr = 20; std::endl;
} }

int main() { int main() {


int x = 10; // Declare a function pointer that can point to a function
std::cout << "Before function call, x = " << x << std::endl; taking a const char* argument and returning void
void (*funcPtr)(const char*);
modifyValue(&x); // Passing address of x to the function
// Assign the address of the printMessage function to our
std::cout << "After function call, x = " << x << std::endl; function pointer
return 0; funcPtr = &printMessage;
}
// Call the function using the function pointer
funcPtr("Hello, Function Pointer!");

return 0;
}
Pointer Arithmetic
#include <iostream> #include <iostream>
using namespace std; using namespace std;
int main() int main()
{ {
int numbers[5] {0, 100, 200, 300, 400}; int a[5]{ 10, 20, 30, 40, 50 };
int * pint = numbers; int* p;
int * p2 = & numbers[3]; for (p = &a[0]; p < &a[5]; p = p + 1)
cout << "pint = " << pint << ", pint+1 = " << pint + 1 {
<< ", sizeof(int) = " << sizeof(int) << endl; cout << *p << " ";
cout << "*(pint+1) = " << * (pint + 1) }
<< ", pint[1] = " << pint[1] << endl; cout << endl;
cout << "*(pint+4) = " << * (pint + 4) return 0;
<< ", pint[4] = " << pint[4] << endl; }
cout << "p2 - pint = " << p2 - pint << endl;
cout << "p2 == pint = " << boolalpha << (p2 == pint) << endl;
cout << "p2 > pint = " << boolalpha << (p2 > pint) << endl;
return 0;
}
#include <iostream>
using namespace std; Pointers to Pointers
int main()
{ #include <iostream>
int a[]{ 10, 20, 30, 40, 50 }; using namespace std;
int* p; int main()
for (p = a; p < a + sizeof(a)/sizeof(a[0]); ++p) {
{ char* alphabet[26]
cout << *p << " "; {
} "alpha",
cout << endl; "bravo",
return 0; "charlie",
} "delta",
"echo",
"foxtrot"
};
for (char **p = alphabet; *p != nullptr; ++p)
{
cout << *p << " ";
}
cout << endl;
return 0;
}
#include <iostream> //Passing by Reference
#include <iostream>
int main() { void increment(int& num) {
int x = 10; num++;
int& ref = x; // Reference to x }
int main() {
ref = 20; // This changes the value of x as well int value = 5;
increment(value);
std::cout << x << std::endl; // Outputs: 20 std::cout << value << std::endl; // Outputs: 6

return 0; return 0;
} }
//Referencing a Pointer
// Referencing with Array #include <iostream>
#include <iostream> int main() {
int main() { int x = 10;
int arr[5] = {1, 2, 3, 4, 5}; int* ptr = &x;
int& thirdElement = arr[2]; int*& refToPtr = ptr; // Reference to a pointer
thirdElement = 10; // Changes arr[2] to 10 *refToPtr = 20; // Changes the value that ptr points to
std::cout << arr[2] << std::endl; // Outputs: 10 std::cout << *ptr << std::endl; // Outputs: 20

return 0; return 0;
} }
#include <iostream> #include <iostream> void myFunction(int x) {
using namespace std; using namespace std;
struct mydata struct mydata
// ...
{ { }
char const * name_;
bool hero_;
char const* name_; void (&refToFunction)(int) =
bool darkside_; myFunction;
};
mydata (char const* name, bool dark)
mydata heroes[]
{ {
{"Spider Man", true}, name_ = name; darkside_ = dark;
{"The Joker", false}, }
{"Doctor Octopus", false}, };
{"Thor", true}, mydata cast[3]
{"Batman", true}, {
{"Loki", false} { "Darth Vader", true },
}; { "Luke Skywalker", false },
void printdata(mydata * p) { "Han Solo", false }
{ };
cout << "Hello. I am " << ( * p).name_ << ". "; void printname(mydata& data)
if (p - > hero_)
{
cout << "I am a hero." << endl;
cout << "Hello. I am " << data.name_ << endl;
else
cout << "I am a villain." << endl; if (data.darkside_)
} cout << "I was seduced by the dark side" << endl;
int main() }
{ int main()
cout << sizeof(mydata) << " " << sizeof(mydata * ) << endl; {
for (mydata * p = heroes; p < heroes + 6; ++p) \ for (mydata& data : cast)
{ {
printdata(p); printname(data);
} }
return 0; return 0;
} }
Chapter 7, Classes and Structs, presents the
fundamentals of structs and classes.
Class: Object:
•A blueprint or template for creating objects. •An instance of a class.
•Defines properties (attributes) and behaviors (methods) that •Represents a real-world entity and encapsulates both data and
objects of the class will have. behavior.
Encapsulation: Abstraction:
•The bundling of data (attributes) and methods that operate on that •Simplifying complex systems by modeling classes based on the
data into a single unit (class). essential properties and behaviors.
•Access to the internal state is controlled by public, private, and •Hides the implementation details and focuses on what an object
protected access specifiers. does rather than how it does it.
Inheritance: Polymorphism:
•A mechanism that allows a new class (derived or child class) to •The ability of different classes to be treated as objects of a common
inherit properties and behaviors from an existing class (base or base class.
parent class). •Includes function overloading and operator overloading, allowing
•Promotes code reuse and establishes an "is-a" relationship. multiple forms of a function or operator.

Function Overloading: Operator Overloading:


•Defining multiple functions with the same name but different •Defining custom behaviors for operators in a class.
parameter lists within a class. •Allows objects to be used with standard operators (+, -, *, etc.) in a
•Enables a class to perform different actions based on the input. meaningful way.

Abstract Class: Interface:


•A class that cannot be instantiated and may contain pure virtual •A collection of method declarations without implementation.
functions. •Classes can implement interfaces, ensuring they provide specific
•Serves as a base class for derived classes to provide a common functionalities.
interface.
Constructor: Destructor:
•A special member function that is automatically called when •A special member function that is automatically called when
an object is created. an object goes out of scope or is explicitly deleted.
•Initializes the object's state. •Cleans up resources allocated by the object.

Friend Function: Overriding:


•A function that is not a member of a class but has access to •Providing a specific implementation for a function in a
its private and protected members. derived class that is already defined in the base class.
•Declared using the friend keyword. •Achieves runtime polymorphism.

Static Binding (Early Binding): Dynamic Binding (Late Binding):


•The association of a function call with a specific function at •The association of a function call with a specific function at
compile time. runtime.
•Occurs with normal (non-virtual) functions and function •Occurs with virtual functions, enabling polymorphism.
overloading.
Pure Virtual Function:
Virtual Function: •A virtual function declared in a base class without providing
•A function declared in the base class with the virtual an implementation.
keyword, allowing it to be overridden by derived classes. •Requires derived classes to provide an implementation.
•Supports dynamic binding.
Friend Class:
Composition: •A class that is granted access to the private and protected
•The act of including an object of one class within another members of another class.
class. •Declared using the friend keyword.
•Allows creating complex objects by combining simpler ones.
#include <iostream>
class MyClass {
public:
// Data members // Member function definition
int data; void MyClass::memberFunction() {
// Member function declaration std::cout << "Inside memberFunction. Data: " << data << std::endl;
void memberFunction(); }
// Constructor
MyClass(int initialData); // Constructor declaration // Constructor definition
// Destructor MyClass::MyClass(int initialData) {
~MyClass(); // Destructor declaration // Initialize data member with the provided value
}; data = initialData;
int main() { std::cout << "Constructor called. Data initialized to: " << data <<
// Creating an object of MyClass std::endl;
MyClass myObject(42); // Calls the constructor }

// Accessing data member and calling member // Destructor definition


function MyClass::~MyClass() {
myObject.data = 99; std::cout << "Destructor called. Data: " << data << std::endl;
myObject.memberFunction(); }
// Destructor is automatically called when the object
goes out of scope
return 0;
}
//Simple Class class MyClass { class MyClass {
class MyClass { public: public:
public: int data; int data;
// Data members
int data; // Member function declaration // Constructor with initialization list
void memberFunction(); MyClass(int initialData) : data(initialData) {
// Member functions // Constructor body
void memberFunction(); // Other member functions... }
};
}; // Member functions...
//With Constructor & // Member function definitions outside the class };
Distractor void MyClass::memberFunction() {
class MyClass { // Implementation... class MyClass {
public: } private:
// Constructor int data;
class MyClass {
MyClass();
private: public:
int privateData; // Friend function declaration
// Destructor
~MyClass(); friend void friendFunction(MyClass obj);
public: };
int publicData;
// Member functions
void memberFunction();
void publicMemberFunction();
};
};
// Friend Class // MyClass2 definition
class MyClass2 {
#include <iostream> public:
// Forward declaration of MyClass2 // Member function that can access private members of
class MyClass2; MyClass1
void modifyMyClass1Data(MyClass1& obj, int newData) {
// MyClass1 declaration obj.privateData = newData;
class MyClass1 { std::cout << "MyClass2 modified MyClass1 privateData to:
private: " << newData << std::endl;
int privateData; }
};
public: int main() {
MyClass1(int data) : privateData(data) {} // Creating objects of MyClass1 and MyClass2
MyClass1 obj1(42);
// Friend class declaration MyClass2 obj2;
friend class MyClass2; // Displaying initial data of MyClass1
obj1.displayData();
// Member function to access privateData
void displayData() { // Modifying privateData of MyClass1 using MyClass2
std::cout << "MyClass1 privateData: " << privateData obj2.modifyMyClass1Data(obj1, 99);
<< std::endl; // Displaying modified data of MyClass1
} obj1.displayData();
}; return 0;
}
Inheritance //Multilevel Inheritance
class Base {
//Multiple Inheritance:
class Base1 {
//Single Inheritance:
// Base class members // Base1 class members };
class Base {
}; class Base2 {
// Base class members
// Base2 class members
};
class Intermediate : public Base { };
// Intermediate class members class Derived : public Base1, public Base2 {
class Derived : public Base {
}; // Derived class members };
// Derived class members
class Derived : public Intermediate {
}; //Virtual Inheritance , Virtual inheritance is used
// Derived class members
}; to resolve ambiguity in multiple inheritance.
//Hybrid Inheritance: class Base {
class A { //Hierarchical Inheritance: // Base class members
// Class A members class Base { };
}; // Base class members class Derived1 : virtual public Base {
class B : public A { }; // Derived1 class members
// Class B members };
}; class Derived1 : public Base { class Derived2 : virtual public Base {
class C : public A { // Derived1 class members // Derived2 class members
// Class C members }; };
}; class FinalDerived : public Derived1, public
class D : public B, public C { class Derived2 : public Base { Derived2 {
// Class D members // Derived2 class members // FinalDerived class members
} }; };
typeid
#include <iostream> int main() {
#include <typeinfo> Base* basePtr = new Derived();

class Base { // Using typeid to get type information


public: const std::type_info& typeInfo = typeid(*basePtr);
virtual ~Base() {}
}; // Comparing type information
if (typeInfo == typeid(Base)) {
class Derived : public Base {}; std::cout << "Object is of type Base\n";
} else if (typeInfo == typeid(Derived)) {
std::cout << "Object is of type Derived\n";
} else {
std::cout << "Object is of unknown type\n";
}

delete basePtr;

return 0;
}
Size of Object
#include <iostream>

class MyClass {
public:
int data;
char character;
double value;
};

int main() {
MyClass obj;

std::cout << "Size of MyClass object: " << sizeof(obj) << " bytes\n";

return 0;
}
“this” pointer – represent current instance of class
#include <iostream>

class MyClass { int main() {


public: MyClass obj1, obj2;
int data;
obj1.setData(42);
void setData(int value) { obj1.displayData();
// Use 'this' pointer to access the member variable of the
current object obj2.setData(100);
this->data = value; obj2.displayData();
}
return 0;
void displayData() { }
// Use 'this' pointer to access the member variable of the
current object
std::cout << "Data: " << this->data << std::endl;
}
};
Abstract:The const keyword in front of a member function // Derived class Rectangle
indicates that the function cannot be called. class Rectangle : public Shape {
private:
#include <iostream>
double length;
// Abstract class declaration
double width;
class Shape {
public:
public:
Rectangle(double l, double w) : length(l), width(w) {}
// Pure virtual function - making Shape an abstract class
// Implementation of the pure virtual function
virtual double area() const = 0;
double area() const override {
// Non-virtual function
return length * width;
void display() const {
}
std::cout << "This is a shape." << std::endl;
};
} };
int main() {
// Derived class Circle // Creating objects of Circle and Rectangle
class Circle : public Shape { Circle circle(5.0);
private: Rectangle rectangle(4.0, 6.0);
double radius; // Calling area function on both objects
public: std::cout << "Circle area: " << circle.area() << std::endl;
Circle(double r) : radius(r) {} std::cout << "Rectangle area: " << rectangle.area() <<
// Implementation of the pure virtual function std::endl;
double area() const override { // Calling the non-virtual function on both objects
return 3.14159 * radius * radius; circle.display();
} rectangle.display();
}; return 0; }
Abstract class: In C++, a pure virtual function is a virtual function in a base class that has no
implementation in the base class and is marked with the = 0 syntax. It serves to declare the
function as an interface that must be implemented by any derived class. A class containing one
or more pure virtual functions is known as an abstract class.
Interfaces : An interface is typically represented by an abstract class with only pure virtual
functions

#include <iostream>

// Abstract interface class


class Interface {
public:
// Pure virtual functions represent the interface contract
virtual void method1() const = 0;
virtual void method2() const = 0;
};
// Concrete class implementing the interface
class ConcreteClass : public Interface { int main() {
public: // Using the interface through a pointer
// Implementation of method1 Interface* interfacePtr = new ConcreteClass();
void method1() const override { interfacePtr->method1();
std::cout << "Implementation of method1 in interfacePtr->method2();
ConcreteClass." << std::endl;
} // Cannot call additionalFunction using the interface pointer
// interfacePtr->additionalFunction(); // Error
// Implementation of method2
void method2() const override { // Using the concrete class directly
std::cout << "Implementation of method2 in ConcreteClass concreteObject;
ConcreteClass." << std::endl; concreteObject.method1();
} concreteObject.method2();
concreteObject.additionalFunction();
// Additional member function
void additionalFunction() const { delete interfacePtr; // Don't forget to delete the dynamically
std::cout << "This is an additional function in allocated object
ConcreteClass." << std::endl;
} return 0;
}; }
Polymorphism is a fundamental concept in object-
oriented programming that allows objects of
different types to be treated as objects of a
common base type. (During Runtime)

This can be achieved through

1. function overloading
2. operator overloading
3. Virtual functions
#include <iostream> // Function that uses polymorphism
#include <vector> void drawShapes(const std::vector<Shape*>& shapes) {
for (const auto& shape : shapes) {
// Base class with a virtual function shape->draw(); // Calls the appropriate draw() based on
class Shape { the actual object type
public: }
virtual void draw() const { }
std::cout << "Drawing a Shape." << std::endl;
} int main() {
}; Circle circle;
Square square;
// Derived class 1
class Circle : public Shape {
// Vector of base class pointers
public:
std::vector<Shape*> shapes;
void draw() const override {
shapes.push_back(&circle);
std::cout << "Drawing a Circle." << std::endl;
shapes.push_back(&square);
}
};
// Drawing shapes using polymorphism
// Derived class 2
drawShapes(shapes);
class Square : public Shape {
public:
return 0;
void draw() const override {
}
std::cout << "Drawing a Square." << std::endl;
}
};
Small Project – Invoice Generation for Sell
#include <iostream> // Employee Class
#include <vector> class Employee {
#include <fstream> public:
#include <sstream> std::string name;
// Product Class
class Product { Employee(const std::string& name) : name(name) {}
public: };
std::string name;
double price;
Product(const std::string& name, double price) : name(name),
price(price) {}
};
// Customer Class
class Customer {
public:
std::string name;
std::string address;
Customer(const std::string& name, const std::string& address)
: name(name), address(address) {}
};
// Invoice Class
class Invoice {
private: // DatabaseManager Class
std::vector<Product> products; class DatabaseManager {
Customer customer;
Employee employee; public:
void saveInvoice(const Invoice& invoice) {
public:
Invoice(const Customer& customer, const Employee& employee) : // For simplicity, save data to a text file
customer(customer), employee(employee) {} std::ofstream file("invoices.txt", std::ios::app);
void addProduct(const Product& product) { file << "Customer: " << invoice.customer.name << "\n";
products.push_back(product); file << "Employee: " << invoice.employee.name << "\n";
}
file << "Products:\n";
double calculateTotal() const {
double total = 0.0;
for (const auto& product : products) { for (const auto& product : invoice.products) {
total += product.price; file << "- " << product.name << " : $" << product.price <<
}
return total; "\n";
} }
void printInvoice() const {
std::cout << "Invoice\n";
std::cout << "Customer: " << customer.name << "\n"; file << "Total: $" << invoice.calculateTotal() << "\n\n";
std::cout << "Employee: " << employee.name << "\n";
std::cout << "Products:\n";
file.close();
for (const auto& product : products) {
std::cout << "- " << product.name << " : $" << product.price << "\n"; }
} };
std::cout << "Total: $" << calculateTotal() << "\n";
}
};
int main() {
// Create instances of Product, Customer, and Employee
Product laptop("Laptop", 999.99);
Product phone("Phone", 399.99);

Customer customer("John Doe", "123 Main St");


Employee employee("Alice");

// Create an Invoice
Invoice invoice(customer, employee);
invoice.addProduct(laptop);
invoice.addProduct(phone);

// Print the Invoice


invoice.printInvoice();

// Save the Invoice to the "database"


DatabaseManager dbManager;
dbManager.saveInvoice(invoice);

return 0;
}
Static @Compile Time
#include <iostream> int main() {
Base baseObj;
class Base { Derived derivedObj;
public:
void display() { Base* ptr = &baseObj;
std::cout << "Base display\n"; ptr->display(); // Calls Base::display() at compile time
}
}; ptr = &derivedObj;
ptr->display(); // Calls Base::display() at compile time (static
class Derived : public Base { binding)
public:
void display() { return 0;
std::cout << "Derived display\n"; }
}
};
Dynamic Binding (Late Binding) @runtime:is
associated with virtual functions.
#include <iostream> int main() {
Base baseObj;
class Base { Derived derivedObj;
public:
virtual void display() { Base* ptr = &baseObj;
std::cout << "Base display\n"; ptr->display(); // Calls Base::display() at compile time
}
}; ptr = &derivedObj;
ptr->display(); // Calls Derived::display() at runtime (dynamic
class Derived : public Base { binding)
public:
void display() override { return 0;
std::cout << "Derived display\n"; }
}
};
Static

Key Points :
•Static members are declared using the static keyword.
•Static data members must be defined outside the class, typically in a source file.
•Static member functions can only access static members (no access to non-static members
directly).
•Static members can be accessed using the class name or an object of the class (though it's
recommended to use the class name for static members).
Note: It's good practice to access static members using the class name rather than an object
#include <iostream>
int main() {
class MyClass { // Accessing static members
public: MyClass::staticVariable = 42;
// Static data member MyClass::staticFunction();
static int staticVariable;
// Creating an object
// Static member function MyClass obj;
static void staticFunction() {
std::cout << "Static function called\n"; // Accessing non-static members using the object
} obj.nonStaticVariable = 10;
obj.nonStaticFunction();
// Non-static data member
int nonStaticVariable; // Accessing static members using the object (not recommended)
obj.staticVariable = 99; // This is legal but not recommended
// Non-static member function obj.staticFunction(); // This is legal but not recommended
void nonStaticFunction() {
std::cout << "Non-static function called\n"; // Accessing static members using the class name (recommended)
} MyClass::staticVariable = 55;
}; MyClass::staticFunction();

// Definition of the static variable return 0;


int MyClass::staticVariable = 0; }

You might also like