C++ FUNDAMENTALS 

(By Dr. Leo Hu)


This handout is suitable for beginners to intermediate learners who study C++ systematically, and it can also be used as a reference tool for common knowledge points of C++.

If you have no knowledge about C++ programming, please go over C++ in 1 hour first. 

Please use this online C++ compiler IDE to test the programs in this handout and develop your own programs in learning.

1.Tools for C++ programming 

When we prepare a C++ program, we must use an editor to write the source code of the program.  Since source code must be pure text (ASCII characters), the editor must be a pure text editor such as Notepad in Windows, or vi in Linux or Unix, etc. 

Any program of source code written in a high-level programming language must be translated into machine code before it can be executed by a computer. There are two ways of translating source code into machine code: compiling and interpreting. 

Compiling is the process of converting source code into machine code before the program is run. Interpreting is the process of translating source code into machine code one line at a time as the program is running.  The tool for compiling is a compiler, and the tool for interpreting is an interpreter. 

C++ is a compiling language. Therefore, we need a C++ compiler to translate a C++ program into machine code. There are quite some C++ compilers available such as GCC (GNU Compiler Collection) , LLVM Clang, etc

Since a C++ program source code may be written in multiple modules stored in a few files, and a program may need use code in predefined libraries, a linker is usually needed to link the modules and libraries together to form an executable program. 

While we can use the independent editor, compiler, and linker in programming, we prefer to use an Integrated Development Environment (IDE) that has integrated the editor, the compiler, and the  linker to work together. There are many IDEs available such as Eclipse IDE for C++, Microsoft Visual C++, C++ Builder, etc., and also many online IDEs such as programiz.com, CodeChef IDE, OnlineGDB, Paiza.io, onecompiler, and so on. 

In this lecture, we will use programiz.com for programming demos and for hands-on practices. The programiz.com IDE in a browser looks like the figure below. 

Figure 1. The programiz.com IDE

It divides the programming space into two columns. The left column lists a few tool buttons on the top, including the Run button that is used to compile and execute the program, and a source code editor below. The right column is the Output space that shows the output result from the program execution.  A Clear button on the top-right corner of the Output space is used to clear the space of Output. 

We will enter C++ program source code in the editor, click the Run button to compile and execute the program, and read the output in the Output space. when necessary, click the Clear button to clear the Output space. 

2.Identifiers 

From here, we will start to learn C++ programming language elements. Identifiers are the most basic elements in a programming langauge. 

An identifier is a name used by the programmer to identify a variable, function, or any other user-defined item. Here are some rules for naming C++ identifiers:

Identifiers are used to name namespaces, variables, named constants, functions, structures, unions, labels, classes, objects, etc.  The identifiers are strings, but most of them, such as the variables, named constants, functions, structures, unions, classes and objects, occupy an amount of memory space, which is determined by a data type. Therefore, before we discuss these identifiers, we should have an overview of data types in C++. 

a. Data Types

Identifiers can be of various data types. The data types determine how many memory bytes (the size of memory) shall be allocated for an item such as a variable or an object in a C++ program.  

C++ has several data types that can be used to store different types of data. The data types in C++ can be divided into three categories: primitive data types, user-defined data types, and derived data types.

Primitive data types are built-in or predefined data types that can be used directly by the user to declare variables. Examples of primitive data types in C++ include integers, characters, floating-point numbers, and Boolean values.

User-defined data types are created by the user using classes and structures. Classes serve as the blueprint for creating objects that encapsulate data members (variables) and member functions (methods). Structures are similar to classes, but they have a few key differences that we will discuss later. 

Derived data types are created by modifying the primitive or user-defined data types. Examples of derived data types in C++ include arrays, pointers, and references.

C++ has seven built-in basic data types such as Boolean (bool), Character (char), Integer (int), Floating Point (float), Double floating point (double), Valueless (void), and Wide character (wchat_t).  The basic data types can be modified with modifiers such as signed, unsigned, short, and long.  As a result,  C++ has the following built-in primitive data types as listed in the table below:

Table 1. Primitive data types of C++ 

As shown in the table, the memory size is described with unit byte, which consists of 8 bits, and a bit is one single digit, either 0 or 1. 

Note: bit is short for binary digit. 

The size of memory occupied by various data types might be different shown in the above table, depending on the compiler and the computer you are using. Let's check the sizes of some frequently used basic data types with the following program. 

Hands-on: Sizes of Data Types

Please enter the C++ program code below in the online C++ compiler (IDE), click Run button and observe the results. 

#include <iostream>

using namespace std;


int main() {

   cout << "Size of char : " << sizeof(char) << endl;

   cout << "Size of bool : " << sizeof(bool) << endl;

   cout << "Size of int : " << sizeof(int) << endl;

   cout << "Size of short int : " << sizeof(short int) << endl;

   cout << "Size of long int : " << sizeof(long int) << endl;

   cout << "Size of float : " << sizeof(float) << endl;

   cout << "Size of double : " << sizeof(double) << endl;

   cout << "Size of wchar_t : " << sizeof(wchar_t) << endl;

   

   return 0;

}

The Output should be something look like

Size of char : 1

Size of bool :  1

Size of int : 4

Size of short int : 2

Size of long int : 8

Size of float : 4

Size of double : 8

Size of wchar_t : 4

When a number is stored in memory, it is stored as either a signed or an unsigned binary format. For example, number 17 has binary value 0b00010001 (The prefix 0b indicates that this is a binary number). 

Note: To differentiate numbers in different number systems, we use 0b prefix for binary numbers, for example, 0b00010001; and 0x for hexadecimal numbers, for example, 0x11. 

If a computer stores a number with 8 bits, that is, 1 byte, the most left bit is the highest bit in the number. The highest bit can be used as a sign bit for the number. In this case, the storage method is called signed. If the highest bit is not used as a sign bit, the storage method is called unsigned. In unsigned storage, 8 bits are all storing bits of value, so that 8 bits can store from 0b00000000 to 0b11111111, that is range of 0 to 255. The example is unsigned char. In signed storage, 8 bits use the highest bit for the sign, the remaining 7 bits for the value, so the storage is from 0b00000000 to 0b01111111, that is, +0 to +127, and from 0b10000000 to 0b11111111, that is -0 to -127. Combining the two parts, the range is -127 to +127. The example is signed char. 

The unsigned data types do not use sign bit so that they do not have negative values and their positive value spaces are doubled.  For example, 1 byte for char (signed char by default) can store data range from -128 (In fact, computers use complementary storage method in order to eliminate -0, so that -0 can be regarded as -128) to 127, while 1 byte for unsigned char can store data range from 0 to 255. The long types use more bytes (or bits) of memory space to store the type of data. For example, long int use 8 bytes to store, more than 4 bytes for int. 

We usually use input/output stream objects cin and cout for input and output in C++ programs (we will discuss later). However, we can also use legacy C-style input and output. In C-style input and output, we should apply format specifiers to tell the program what types of data is being processed. 

Format specifiers are used to specify what type of data is to be accepted by the predefined function scanf(), and what type of data is to be displayed by the predefined function printf(). For example, in statement 

scanf("%d", &num);

an integer is to be accepted from the input because the input data format specifier is %d, which is for int. And in statement

printf("%s", my_str);

shows a string is to be printed because the output data format specifier is %s, which is for string

Here are some frequently used C++ format specifiers:

- `%d`: Signed decimal integer.

- `%i`: Signed decimal integer.

- `%u`: Unsigned decimal integer.

- `%o`: Unsigned octal.

- `%x`: Unsigned hexadecimal integer (lowercase).

- `%X`: Unsigned hexadecimal integer (uppercase).

- `%f`: Decimal floating point.

- `%e`: Scientific notation (mantissa/exponent), lowercase.

- `%E`: Scientific notation (mantissa/exponent), uppercase.

- `%g`: Use the shortest representation: %e or %f.

- `%G`: Use the shortest representation: %E or %F.

- `%c`: Character.

- `%s`: String of characters.

Beside the legacy data types from C as listed in Table 1 above, C++ has a bool data type, which can take the values true or false. A Boolean variable is declared with the bool keyword and can only take the values true or false (C++ Booleans (w3schools.com)). C++ compiler display 1 for true, and 0 for false. When a value is provided to be judged, 0 will be false, any non-zero will be true. For example (please test it in the online C++ compiler (IDE))

#include <iostream>

using namespace std;


int main() {

  bool isCodingFun = true;

  bool isFishTasty = false;

  cout << isCodingFun << endl;

  cout << isFishTasty <<endl;

 

  int zeroVar = 0;

  int nonZeroVar = 10;

  if(!zeroVar)cout << "0 is false"<<endl;

  if(nonZeroVar)cout << "non zero is true"<<endl;

 

  return 0;

}

This program will output

1

0

0 is false

non zero is true

Type casting is another important topic about data types. Type casting (or type conversion) is a way to convert a value from one data type to another data type.  Type conversion (type promotion) takes place to avoid loss of data.  User-defined data types are designed by the user to suit their requirements, the compiler does not support automatic type conversions for such data types therefore, the user needs to design the conversion routines by themselves if required.  In C++, there are two types of type conversion: Implicit type conversion and Explicit type conversion. 

Implicit type casting in C++ is also known as ‘automatic type conversion’ and is done by the compiler on its own, without any external trigger from the user. It generally takes place when in an expression more than one data type is present. In such condition type conversion (or type casting, type promotion) takes place to avoid loss of data. All the data types of the variables are upgraded to the data type of the variable with largest data type. Lower data type refers to the data type that occupies less memory space and has a smaller range of values than the higher data type. Higher data type refers to the data type that occupies more memory space and has a larger range of values than the lower data type. The level of data types from lower to higher is as follows: bool, char, short int, int, unsigned int, long int, unsigned long, long long, float, double,  and long double.

Hand-on:

Please enter the C++ program code in the online C++ compiler (IDE), run and observe implicitly type conversion.

#include <iostream>

using namespace std;


int main() {

    char c = 'a';    

    int i = 10;

    double f = 3.14;


    cout << "Value of c: " << c << endl;

    cout << "Size of c: " << sizeof(c) << endl;

    cout << "Value of i: " << i << endl;

    cout << "Size of i: " << sizeof(i) << endl;

    cout << "Value of f: " << f << endl;

    cout << "Size of f: " << sizeof(f) << endl;


    // Implicit type conversion

    i = c;

    cout << "Value of i after implicit type conversion: " << i << endl;

    cout << "Size of i: " << sizeof(i) << endl;

    f = i;

    cout << "Value of f after implicit type conversion: " << f << endl;

    cout << "Size of f: " << sizeof(f) << endl;

    return 0;

}

If there is no issue, the output should look like:

Value of c: a

Size of c: 1

Value of i: 10

Size of i: 4

Value of f: 3.14

Size of f: 8

Value of i after implicit type conversion: 97

Size of i: 4

Value of f after implicit type conversion: 97

Size of f: 8

We can see that a char type is 1 byte, int type is 4 bytes, and a double type is 8 bytes. At i = c, the data type of c's value is implicitly converted to variable i's type, that is, int; and at f = c, the data type of c's value is implicitly converted to variable f's type, that is, double. 

Explicit type casting in C++ is a process of converting one data type to another data type explicitly. Explicit type conversion is done by using the casting operator. There are four types of casting operators in C++: static_cast, dynamic_cast, const_cast, and reinterpret_cast 

`static_cast` is used for conversions between basic types and can handle conversions between related classes or between numeric types. `dynamic_cast` is used for conversions between polymorphic types (types that have at least one virtual function, which we will discuss later). `const_cast` is used to remove or add const or volatile qualifiers from a variable. `reinterpret_cast` is used to convert one pointer type to another pointer type, even if the types are unrelated.

Here is an example of explicit type conversion in C++ (you can test in the online C++ compiler (IDE)):

#include <iostream>

using namespace std;


int main() {

    int i = 7;

    float f = 3.14;


    cout << "Value of i: " << i << endl;

    cout << "Value of f: " << f << endl;


    // Explicit type conversion

    f = static_cast<float>(i);

    cout << "Value of f after explicit type conversion: " << f << endl;


    return 0;

}

If there is no issue, the output of the program execution should look like:

Value of i: 7

Value of f: 3.14

Value of f after explicit type conversion: 7

In this example, a static conversion operator is used to convert variable i from its original data type, int, to the float data type. 

b. Namespaces 

In C++, a namespace is a declarative region that provides a scope to the identifiers (names of the data types, function, variables, etc.) inside it. It is used to organize code into logical groups and to prevent naming conflicts. According to the Google C++ Style Guide, namespace names should be

A namespace is defined using the syntax 

namespace namespace_name { /* declarations */ }

Variables, functions, and other named entities can be defined inside the namespace. To access the named entities from outside the namespace, we use the namespace_name:: prefix. There are several advantages of using namespaces in C++, such as avoiding naming conflicts, making code more readable and maintainable, and improving code organization. 

Hands-on:

Please enter the program code below in the online C++ compiler (IDE), run and think of how a namespace is defined and used.

#include <iostream>


// Define a namespace

namespace my_namespace {

    int x = 10; //declare a variable, x

    //define a function, printX()

    void printX() {

        std::cout << "x = " << x << std::endl; //use the predefined namespace std

    }

}


int main() {

    // Access the named entities inside the namespace

    my_namespace::printX();


    // Change the value of x

    my_namespace::x = 20;


    // Access the named entities inside the namespace again

    my_namespace::printX();


    return 0;

}

If there is no issue, the Output of the above program should look like:

x = 10

x = 20

In this program, printX() and x are declared or defined in namespace my_namespace. 

Question: if the namespace prefix my_namespace:: is removed from the first statement in main(), what shall happen?  please do and see.

Answer: an error shall appear - error: 'printX' was not declared in this scope; did you mean 'my_namespace::printX'?

Question: if the namespace prefix my_namespace:: is removed in the main(), add statement 

using namespace my_namespace;

before the main() function, what shall happen? 

Answer: there is no error about namespace, which means, the program code below is the same as the above (please test in the online C++ compiler (IDE)):

#include <iostream>


// Define a namespace

namespace my_namespace {

    int x = 10;

    void printX() {

        std::cout << "x = " << x << std::endl;

    }

}


using namespace my_namespace;


int main() {

    // Access the named entities inside the namespace

    printX();


    // Change the value of x

    x = 20;


    // Access the named entities inside the namespace again

    printX();


    return 0;

}

The above example and practice show that, we can define our own namespace, and add definitions of other language elements in the defined namespace. Then we can use the defined language elements in the namespace in our program with prefix, defined_namespace::, to the defined elements. If we do not want to use the prefix, we can add the "using namespace" statement before the main() function. 

c. Variables 

A variable in C++ is a name given to a memory location that stores data or values that are changeable and to be used in the program later for execution.  According to GeeksforGeeks, the following are some common naming conventions for variables:

- Use lowercase letters for variable names. 

- Use underscores between words in variable names.

- Use descriptive names that are meaningful for the variables.

- Avoid using single-letter variable names.

A variable can be defined using the combination of letters, digits, or special symbols like underscore (_), defined by using the data types like char, int, float, or double. In C++, there are different types of variables, which are defined with different keywords, for example:

To create a variable, specify the type and assign it a value in a declaration statement:

type variableName = value;

Where type is one of C++ data types (such as int), and variableName is the name of the variable (such as x or myName). The equal sign (=) is used to assigns a value to the variable. For example:

int myNum = 15;

We can also declare a variable without assigning the value, but assign the value later:

    int myNum;

    myNum = 15;

Note: if a new value is assigned to an existing variable, it will overwrite the previous value. 

Tip: Good programming practice suggests assigning an initial value to a variable at declaration to help avoid bugs and make your code more readable and maintainable. 

Note: A declaration statement may declare more than one variable, and separate them with comma (,). Some or all of them may be assigned with initial values. For example, we can declare two integer variables in one statement like

     int myInteger1 = 5, myInteger2 = 0;

Note: C++ naming convention requires that variables start with a lower-case letter.

d. Named Constants 

A named constant is a name of a memory location that stores a data whose value cannot be changed during the execution of the program. A named constant can be used in much the same way as a variable, except that its value cannot be changed in program execution, so that it is also known as a "const variable".  

In C++, naming conventions for named constants vary depending on the project's coding conventions. According to Learn C++, some common naming conventions for named constants include:

- Use underscored, upper-case names (e.g. `EARTH_GRAVITY`).

- Use intercapped names with a 'k' prefix (e.g. `kEarthGravity`).

- Use CamelCase (e.g. `EarthGravity`).

To declare a named constant in C++, you can use the keyword const followed by the data type and the name of the constant. Here is an example:

const int MAX_VALUE = 100;

In this example, we declare a named constant `MAX_VALUE` of type `int` and initialize it to 100. Once a named constant is declared, its value cannot be changed during the execution of the program. There are different naming conventions for named constants in C++. For example, some programmers use all caps for named constants, while others use a `k` prefix followed by mixed case. The most important thing is to be consistent with your naming convention throughout your code.

Here is an example of defining and using a named constant in C++ (please test it in the online C++ compiler (IDE):

#include <iostream>

using namespace std;


int main() {

    const int MAX_VALUE = 100;

    int myNum = 50;


    if (myNum > MAX_VALUE) {

        cout << "Error: myNum is greater than MAX_VALUE." << endl;

    } else {

        cout << "myNum is less than or equal to MAX_VALUE." << endl;

    }


    return 0;

}

In this example, we define a named constant `MAX_VALUE` of type `int` and initialize it to `100`. We also declare an integer variable `myNum` and initialize it to `50`. We then use an `if` statement to compare the value of `myNum` with the value of `MAX_VALUE`. If `myNum` is greater than `MAX_VALUE`, we print an error message. Otherwise, we print a message indicating that `myNum` is less than or equal to `MAX_VALUE`.

e. Functions 

In C++, a function is a named block of code that performs a specific task. It is a self-contained module of code that can be called by other parts of the program. Functions are used to break down large programs into smaller, more manageable pieces, and to reuse code throughout the program. The function name is the identifier for the function. 

In C++, naming conventions for functions vary depending on the project's coding conventions. According to Stack Overflow, there is no one correct way to name functions in C++. However, some common naming conventions include:

- Use lowercase letters for function names.

- Use underscores between words in function names.

- Use intercapped names (e.g. `myFunction`).

Every C++ program has at least one function, that is function main(). The main() function is the entry point of a program and is not a member of any class. It is a global function that can be defined outside of any class. The main() function is called by the operating system when the program starts and returns an integer value to the operating system when it exits. For example, Microsoft Windows operating systems has defined

0 - success

1 - Informational

2 - Warning

3 - Error

Therefore, statement 

    return 0;

means the program has completed with success. Other operating systems have the same effect. 

In C++, functions are declared using the syntax 

type function_name(parameters) { /* function body */ }`

The type specifies the data type of the value returned by the function, function_name is the name of the function, and parameters are the input parameters to the function. The function body contains the code that performs the task of the function. Here is an example of a simple C++ function that adds two numbers:

int add(int x, int y) {

    return x + y;

}

In this example, we define a function called add that takes two integer parameters x and y, and returns their sum. We can call this function from other parts of the program to add two numbers. 

f. Structs

In C++, a structure is a user-defined data type that groups related data together.  It is similar to an array, but unlike an array, a structure can contain variables of different data types. A structure is defined using the struct keyword followed by the name of the structure and a set of braces containing the variables that make up the structure. Once a structure is defined, you can create variables of that type and access its members using the dot operator (.). Structures are useful for organizing related data into a single unit and passing that data between functions or modules in a program.

In C++, naming conventions for structs vary depending on the project's coding conventions. According to Stack Overflow, there is no one correct way to name structs in C++. However, some common naming conventions include:

- Use Pascal and Camel casing for struct names.

- Do not use Hungarian notation or add any other type identification to struct names.

- Do not prefix member fields.

The syntax of defining a struct in C++ is as follows:

struct struct_name {

    data_type1 member_name1;

    data_type2 member_name2;

    .

    .

    .

    data_typeN member_nameN;

};

In this syntax, `struct_name` is the name of the structure, and `member_name1`, `member_name2`, ..., `member_nameN` are the names of the members of the structure. Each member has a data type specified by `data_type1`, `data_type2`, ..., `data_typeN`. The members are separated by semicolons. Here is an example of a struct in C++:

struct Person {

    std::string name;

    int age;

    double height;

};

In this example, we define a struct called `Person` that has three members: a string member called `name`, an integer member called `age`, and a double member called `height`. We can create variables of this type and access its members using the dot operator.

Hands-on:

Please enter the program in the online compiler's editor and run it to see the effect. 

#include <iostream>

#include <string>


// Define a struct

struct Person {

    std::string name;

    int age;

    double height;

};


int main() {

    // Create a variable of the struct type

    Person person1;


    // Assign values to the members of the struct variable

    person1.name = "John";

    person1.age = 30;

    person1.height = 6.0;


    // Print the values of the members of the struct

    std::cout << "Name: " << person1.name << std::endl;

    std::cout << "Age: " << person1.age << std::endl;

    std::cout << "Height: " << person1.height << std::endl;


    return 0;

}

If nothing goes wrong, the output should look like

Name: John

Age: 30

Height: 6

In this example, we define a struct called `Person` that has three members: a string member called `name`, an integer member called `age`, and a double member called `height`. We then create a variable of this type called `person1` and assign values to its members. Finally, we print the values of the members of the struct using `std::cout`.

Note:  A struct member such as the person's name is accessed by the struct variable (person1), the dot operator (.), and the member variable (name, in this case): person1.name. Similarly, the person's age is accessed by person1.age, and the person's height is accessed by person1.height. 

g. Unions 

A union is a user-defined type in C++ that allows you to store different data types in the same memory location. This means that at any given time, only one of a union members can exist. It also means that a union will use only enough memory to store the largest member no matter how many members it has.

There is no specific naming convention for unions in C++. However, it is recommended to follow the same naming conventions as for other types of variables. 

Here is an example of a union in C++ (please test it in the online C++ compiler (IDE)):

#include <iostream>

using namespace std;


union MyUnionType {  //define a union type

  int i;

  float f;

  char c;

};


int main() {

  MyUnionType myUnion; //use the union type to declare a variable, myUnion

  myUnion.i = 42; //an integer is put in the myUnion space

  cout << myUnion.i << endl; // Output: 42

  myUnion.f = 3.14; //a float is put in the myUnion space

  cout << myUnion.f << endl; // Output: 3.14

  myUnion.c = 'A'; //a char is put in the myUnion space

  cout << myUnion.c << endl; // Output: A

}

The execution output should be 

42

3.14

A

In this example, we define a union called MyUnionType that has three members: an integer `i`, a float `f`, and a character `c`. We then create an instance of the union called `myUnion` and set its integer member to `42`. We then output the value of the integer member using `cout`. We then set the float member to `3.14` and output its value. Finally, we set the character member to `'A'` and output its value.

Note: The members of a union share the same memory location, so only one member can be used at a time. 

h. Labels 

In C++, a label is an identifier followed by a colon (:) that is used to mark a position in the code. The `goto` statement force the execution unconditionally jumping to the labeled statement. The `goto` statement must be in the same function as the label it is referring to, and it may appear before or after the label. However, the use of `goto` statements is generally discouraged in modern C++ programming because it can make code difficult to read and maintain. 

In C++, naming conventions for labels vary depending on the project's coding conventions. 

Here is an example of using a label in C++:

#include <iostream>

using namespace std;


int main() {

    int i = 0;


    // Define a label

    start:


    cout << i << endl;

    i++;


    if (i < 10) {

        goto start;

    }


    return 0;

}

In this example, we define a label called `start` using the syntax `start:`. We then use a `goto` statement to transfer control to the labeled statement. The `goto` statement must be in the same function as the label it is referring to, and it may appear before or after the label. In this example, we use the `goto` statement to print the value of `i` and increment it until it reaches `10`. 

i. Classes

A class name is an identifier. In C++, a class is a user-defined type or data structure declared with the keyword `class` that has data and functions (also called member variables and member functions) as its members. We will discuss classes later. Identifiers for classes are similar to identifiers for other user-defined items. They can be composed of letters, digits, and underscores, but they must begin with a letter or an underscore. Identifiers for classes are case-sensitive, which means that MyClass and myclass are two different identifiers. 

In C++, naming conventions for classes vary depending on the project's coding conventions. According to the Google C++ Style Guide, class names should start with a capital letter and have a capital letter for each new word. No underscores should be used. For example:

class MyClass {

  // code here

};

In this example, class name is MyClass, which is the class's identifier. 

Classes are useful for organizing related data and functions into a single unit and passing that data between functions or modules in a program. I will discuss classes specifically later

j. Objects

An object name is an identifier. In C++, an object is an instance of a class. It is a variable of the class type that can store data and call member functions defined in the class. 

In C++, naming conventions for objects vary depending on the project's coding conventions. 

For example,  suppose we have a class name is MyClass. To declare an object of this class, we may have an object declaration statement look like

MyClass my_object;

We will discuss objects specifically later

k. Scope: Local vs. Global 

The scope of an identifier determines whether the identifier can only be accessed and modified inside a specific block of code, or all over the program. 

In C++, local variables are declared within subroutines or programming blocks, and their local scope means they can only be used within the subroutine or program block they were declared in. Global variables, on the other hand, are declared at the start of the program, and their global scope means they can be used in any procedure or subroutine all over in the program.

Here is an example of using local and global variables in C++ (you can test it in the online C++ compiler (IDE)):

#include <iostream>

using namespace std;


// Define a global variable

int global_var = 10;


int main() {

    // Define a local variable

    int local_var = 20;


    // Print the values of the variables

    cout << "Global variable: " << global_var << endl;

    cout << "Local variable: " << local_var << endl;


    // Change the value of the variables

    global_var = 30;

    local_var = 40;


    // Print the values of the variables again

    cout << "Global variable: " << global_var << endl;

    cout << "Local variable: " << local_var << endl;


    return 0;

}

The execution result should be

Global variable: 10

Local variable: 20

Global variable: 30

Local variable: 40

In this example, we define a global variable called `global_var` and initialize it to `10`. We also define a local variable called `local_var` and initialize it to `20`. We then print the values of both variables using `cout`. We change the value of both variables and print their values again. If there is another function, the global_var can be used in the other function, but the local_var shall not be used. 

3.Operators 

Operators are used to perform operations on variables and values (Swiniarski, C | Operators | Codecademy). 

In terms of the number of operands an operator works on, C++ has unary operators, which as only one operand, such as increment (++), decrement (--), unary plus (+), unary minus (-), logical not (!), bit 1's complement(~), sizeof(), type casting operator (type), address operator (&), and pointer operator (*), etc., binary operators, which  has two operands, such as addition (+), subtraction (-), logical and (&&), assignment (=), etc., and a ternary operator, the conditional operator (?:), which has three operands. This is very easy to see from the expressions that the operators are used. 

In terms of the associativity of operators, C++ has left-to-right and right-to-left operators. In C++ programming language, the associativity of an operator determines the direction in which an expression is evaluated. In C++, the operators that have right to left associativity are assignment operators, unary operators, and the ternary operator. All other operators are left to right. 

In terms of an operator's performance, C++ divides the operators into the following six groups: arithmetic, relational (or comparison), logical, bitwise, assignment, and other operators. We will discuss more on operators from this perspective. 

Finally, operator precedence is critical in determining the order in which operators are evaluated in an expression. Operators with higher precedence are evaluated first. I will list the operator precedence after discussing the operators' performances

a. Arithmetic Operators 

Arithmetic operators are used to perform arithmetic/mathematical operations on operands 

( Abhinav96, 2020)  (Operators in Julia - GeeksforGeeks). Arithmetic operators include addition, subtraction, multiplication, division, modulus, increment, decrement, unary plus, and unary minus. The first five operators perform exactly the same as in mathematics. Increment increases its operand's value by 1, and decrement decreases its operand's value by 1. Unary plus operator simply returns the value of its operand,  while unary minus operator returns the negative value of its operand. The C++ arithmetic operators are listed in the table below. 

Table 2. C++ Arithmetic operators

Note: the increment operator and the decrement operator have two cases, pre- or post-.  pre-increment increments the value of the variable before it is used in an expression, whereas post-increment increments the value of the variable after it is used in an expression. For example, if a = 5, b = ++a is equivalent to a = a +1, then b = a so that the results are a = 6, b = 6. Whereas if a = 5, b = a++ is equivalent to b = a, then a = a+1 so that the results are a = 6, b = 5. 

pre-decrement and post-decrement have similar difference. For example, if a = 5, b = --a is equivalent to a = a-1, then b = a so that the results are a = 4, b = 4.  Whereas if a = 5, b = a-- is equivalent to b = a, then a = a - 1 so that the results are a = 4, b = 5. 

Hands-on: arithmetic operators

Please enter the program below in the online C++ compiler (IDE), run and think of the results. Do you understand why?

/*Demo on arithmetic operators*/

#include <iostream>

using namespace std;

int main() {

    //declare a few variables

    int a = 30, b = 3, c = 0;

    //Test arithmetic operators

    cout << "when a = " << a << ", b = " << b << ", c = a + b is " << a + b << endl;

    cout << "when a = " << a << ", b = " << b << ", c = a - b is " << a - b << endl;

    cout << "when a = " << a << ", b = " << b << ", c = a * b is " << a * b << endl;

    cout << "when a = " << a << ", b = " << b << ", c = a / b is " << a / b << endl;

    cout << "when a = " << a << ", b = " << b << ", c = a % b is " << a % b << endl;

    a = 30;

    c = ++a;

    cout << "a = 30, after c = ++a, a = " << a << ", c = " <<  c << endl;  

    a = 30;

    c = a++;

    cout << "a = 30, after c = a++, a = " << a << ", c =" << c << endl;  

    a = 30;

    c = +a;

    cout << "a = 30, after c = +a, a = " << a << ", c = " << c << endl;  

    a = 30;

    c = -a;

    cout << "a = 30, after c = -a, a = " << a << ", c =" << c << endl;  

   

    return 0;

}

If nothing goes wrong, the output should look like:

when a = 30, b = 3, c = a + b is 33

when a = 30, b = 3, c = a - b is 27

when a = 30, b = 3, c = a * b is 90

when a = 30, b = 3, c = a / b is 10

when a = 30, b = 3, c = a % b is 0

a = 30, after c = ++a, a = 31, c = 31

a = 30, after c = a++, a = 31, c =30

a = 30, after c = +a, a = 30, c = 30

a = 30, after c = -a, a = 30, c =-30

b. Relational Operators 

Relational operators are used for the comparison of the values of two operands. They are also called comparison operators. The return value of a comparison is either 1 or 0, which means true (1) or false(0) (C++ Comparison Operators (w3schools.com) ).  These values are known as Boolean values. There are 6 relational operators as listed in the table below. 

Table 3. C++ Relational (or comparison) operators

Relational operators are critical in C++ to construct conditional expressions for making decision. We will discuss them more soon. 

c. Logical Operators 

Logical Operators are used to combine two or more conditions/constraints or to complement the evaluation of the original condition in consideration (Operator – ACE IT SKILLS (master-engineer.com) ). There are a total of 3 logical operators in C programming language and they are listed in the table below:

Table 4. C++ Logical operators

Logical operators are also critical in C++ to construct conditional expressions for making decisions. We will discuss them later

d. Bitwise Operators 

The Bitwise operators are used to perform bit-level operations on the operands (Operators in C - GeeksforGeeks ). There are 6 bitwise operators as listed in the table below:

Table 5. Bitwise operators

The examples in the table above assume character int variable A holds 60, that is binary 0b00111100, and variable B holds 13, that is binary 0b00001101. 

Note: to differentiate numeric values in different number systems such as decimal, binary, and hexadecimal number systems, we may use prefix 0b for binary values, and 0x for hexadecimal values. 

In A & B, A is 0b00111100, B is 0b00001101, the result's bits from left to right will be 

0 & 0 = 0

0 & 0 = 0

1 & 0 = 0

1 & 0 = 0

1 & 1 = 1

1 & 1 = 1

0 & 0 = 0

0 & 1 = 0

so the result is 0b00001100, or 12. 

In ~A, the result's bits from left to right are flipped from those in A, that is, 

~0 = 1

~0 = 1

~1 = 0

~1 = 0

~1 = 0

~1 = 0

~0 = 1

~0 = 1

so the result is 0b11000011 = -2^7 + 2^6 + 2^1 + 2^0 = -61.

In A << 2, the result's bits from left to right are left shifting two positions from A, that is,

0b00111100 << 2 is 0b111100, or 240.

In A >> 2, the result's bits from left to right are right shifting two positions from A, that is,  0b00111100 >> 2 is 0b00001111, or 15. 

Let's run a lab to better understand these bitwise operators. 

Hands-on:

Please enter the program below in the online C++ compiler, run and think of the results. 

/*Test bitwise operators*/

#include <iostream>


int main() {

  int a = 0b1010;

  int b = 0b1100;


  std::cout << (a & b) << std::endl; // bitwise AND

  std::cout << (a | b) << std::endl; // bitwise OR

  std::cout << (a ^ b) << std::endl; // bitwise XOR

  std::cout << (~a) << std::endl; // bitwise NOT

  std::cout << (a << 1) << std::endl; // left shift

  std::cout << (b >> 1) << std::endl; // right shift


  return 0;

}

If nothing goes wrong, the output should look like:

8

14

6

-11

20

6

Why? Since a = 0b1010 or 0b00001010, b = 0b1100 or 0b00001100, 

a & b = 0b00001010 & 0b00001100 = 0b00001000 = 8,

a | b = 0b00001010 | 0b00001100 = 0b00001110 = 14,

a ^ b = 0b00001010 ^ 0b00001100 = 0b00000110 = 6,

~a = ~(0b00001010) = 0b11110101 = -11

Note:  Why 0b11110101 is -11? It is because the number is evaluated in Two's complement for signed data. In computer's Two's complement, the highest bit is the sign - 0 marks a positive number, and 1 marks a negative number.  When a number is positive, we can obtain the value directly. When a number is negative, we obtain the value following a few steps: i). Invert (flip) all bits in the number. That is, changing every 0 to 1, and every 1 to 0. ii). add 1 to the entire inverted number. iii). convert the result to decimal value.  Therefore, in 0b11110101, the highest bit is 1, so it is a negative number. To get a negative number's value, we need invert (or flip) all bits, it becomes 0b00001010, then add 1 to the entire inverted number, it becomes 0b00001011, which is value 11. Therefore, 0b11110101 = -11.

a << 1 produces 0b00010100 = 20

b >> 1 produces 0b00000110 = 6

e. Assignment Operators 

Assignment operators are used to assign values to variables. They are all binary operators. All C++'s assignment operators are listed in the table below:

Table 6. C++ Assignment operators

The basic assignment operator (=) is different from the equal sign (=) in mathematics. It assigns the value on the right side to the variable on the left side (Numeric Variables | Phonetics on Speed (lingphon.net) ). For example, 

int a = 21;

This statement assigns the value 21 to the variable a so that variable a holds 21. Later, a can be assigned with other values. 

Beside the basic assignment operator, C++ provides many compound assignment operators which combine other operations with the basic assignment operation. For example, +=, -=, *=, /=, and %= combine arithmetic operations with assignment. >>= , <<= &=, ^=, and |= combine bitwise operations with assignment.  These compound assignment operators work in the same sequence - the value of the variable on the left side of the operator works with the value on the right side of the operator, and then assign the result to the variable on the left side. For example, 

int a = 21;

a += 5;

The operation of a += 5 is equivalent to 

a = a + 5.

Similarly, a <<= 2 is equivalent to a = a << 2, where the right side works first, then assigns the result to the left side because assignment operator has a lower-level precedence than the bitwise operators. 

To better understand these assignment operators, let's work on a lab. 

Hands-on:

Please enter the program below in the online C++ compiler, run and think of the results. Does it make sense

/*Test assignment operators*/

#include <iostream>


using namespace std;


int main() {

   int a = 21;

   int c ;

   cout << "originally, a = 21" << endl;

   c =  a;

   cout << "=  Operator Example: c = a, Value of c = " << c << endl;

   c +=  a;

   cout << "+= Operator Example: c += a, Value of c = " << c << endl;

   c -=  a;

   cout << "-= Operator Example: c -=  a, Value of c = " << c << endl;

   c *=  a;

   cout << "*= Operator Example: c *=  a, Value of c =" << c << endl;

   c /=  a;

   cout << "/= Operator Example: c /=  a, Value of c = " << c << endl;

   c  = 200;

   c %=  a;

   cout << "%= Operator Example: c = 200, c %= a,  Value of c = " << c << endl;

   c <<=  2;

   cout << "<<= Operator Example: c <<=  2, Value of c = " << c << endl;

   c >>=  2;

   cout << ">>= Operator Example: c >>=  2, Value of c = " << c << endl;

   c &=  2;

   cout << "&= Operator Example: c &=  2, Value of c = " << c << endl;

   c ^=  2;

   cout << "^= Operator Example: c ^=  2, Value of c = " << c << endl;

   c |=  2;

   cout << "|= Operator Example: c |=  2; Value of c = " << c << endl;

   

   return 0;

}

If nothing goes wrong, the result should look like 

originally, a = 21

=  Operator Example: c = a, Value of c = 21

+= Operator Example: c += a, Value of c = 42

-= Operator Example: c -=  a, Value of c = 21

*= Operator Example: c *=  a, Value of c =441

/= Operator Example: c /=  a, Value of c = 21

%= Operator Example: c = 200, c %= a,  Value of c = 11

<<= Operator Example: c <<=  2, Value of c = 44

>>= Operator Example: c >>=  2, Value of c = 11

&= Operator Example: c &=  2, Value of c = 2

^= Operator Example: c ^=  2, Value of c = 0

|= Operator Example: c |=  2; Value of c = 2


f. Other Operators 

Operators that are not categorized in the above groups are discussed here. These include stream operators, type casting operator, sizeof operator, conditional operator, address operator, pointer operator, comma operator, structure pointer operator, subscript operator, function call operator, etc.

In C++, the stream operators are used to read and write data from and to streams. Stream insertion operator<<” is used for output and stream extraction operator>>” is used for input. They are originally used for bitwise shift and are overloaded to work with user-defined types such as an object. Some examples of using "<<" and ">>" for output and input streams can be found in the above labs. They are left to right associative operators.

In C++ programming, the type casting operator is used to convert a variable from one data type to another data type. It was discussed in the section of type casting earlier in this lecture. The type casting operator is viewed as a whole thing with its operand, so it is regarded as a right to left associative operator. 

In C++ programming language, the sizeof operator is a compile-time unary operator that can be used to compute the size of its operand. It returns the size of a variable or data type in bytes.  The result of sizeof is of the unsigned integral type which is usually denoted by size_t (sizeof operator in C - GeeksforGeeks). for example, 

#include <iostream>

using namespace std;


int main() {

   int arr[10];

   cout << "Size of int: " << sizeof(int) << " bytes" << endl;

   cout << "Size of arr: " << sizeof(arr) << " bytes" << endl;

   return 0;

}

This program will output 

Size of int: 4 bytes

Size of arr: 40 bytes

The sizeof operator can be applied to any data type, including primitive types such as integer and floating-point types, pointer types, or compound data types such as Structure, union, etc.

The sizeof operator is a unary operator and is considered a right to left associative operator.

In C++ programming language, the conditional operator (?:) is a ternary operator that works on three operands. It works similarly to the if-else statement (we will discuss soon) and executes the code based on the specified condition. The syntax of conditional operator is: 

testCondition ? expression1 : expression2;

The testCondition is a Boolean expression that results in either true or false. If the condition is true - expression1 (before the colon) is executed; if it’s false - expression2 (after the colon) is executed. The conditional operator takes 3 operands (The testCondition, expression1 and expression2). Hence, the name ternary operator.  The conditional operator is viewed as a whole with its operands, so it is also regarded as right to left associative operator. 

For example, 

int x = 10;

int  y = 5;

int z = (x > y) ? x : y; // z is now 10

z should be 10 because x > y is true, x is used to be assigned to z. 

In C++ programming language, the address operator is a unary operator that returns the memory address of its operand. The address operator is denoted by the ampersand symbol (&). For example:

#include <iostream>

using namespace std;


int main() {

   int var = 5;

   cout << "Value of var: " << var << endl;

   cout << "Address of var: " << &var << endl;

   return 0;

}

This will output 

Value of var: 5

Address of var: 0x7ffeedb4d9c4

Memory address is represented with a hexadecimal number. The address operator can be used with any variable or array element in C++.

The address operator is also used to declare a reference variable. A reference variable is a "reference" to an existing variable.  For example (please test in the online C++ compiler (IDE)):

,

#include <iostream>

#include <string>

using namespace std;


int main() {

  string food = "Pizza";

  string &meal = food;  //declare a reference variable meal, which is denoted by &


  cout << food << "\n";

  cout << meal << "\n";

  return 0;

}

This program will output 

Pizza 

Pizza

Note:  if variable meal is declared as 

string meal = food;

The output will be the same as above. So, what's the difference? When meal is declared as a reference, it is a reference to (or say, a label on) string variable food. That means, meal does not have its own memory space. But when meal is declared as a string, it is an independent variable, and it obtains memory space. It receives a copied value from variable food. 

The address operator is regarded as a whole thing with its operand, so that it is regarded as a right to left associative operator. 

A pointer is to store the memory address of another variable. When we declare a pointer variable, we use the pointer operator, asterisk (*) symbol, before the variable name. For example (please test in the online C++ compiler (IDE))

#include <iostream>

using namespace std;


int main() {

   int var = 5;

   int *ptr = &var;

   cout << "Value of var: " << var << endl;

   cout << "Address of var: " << &var << endl;

   cout << "Value of ptr: " << ptr << endl;

   cout << "Value pointed to by ptr: " << *ptr << endl;

   return 0;

}

This will output 

Value of var: 5

Address of var: 0x7ffeedb4d9c4

Value of ptr: 0x7ffeedb4d9c4

Value pointed to by ptr: 5

The pointer operator is also used to deference a pointer variable. To dereference a pointer variable means to access the value stored in the memory address pointed by the pointer. We use the asterisk (*) symbol before the pointer variable name to dereference it. For example, if p points to an integer variable, then *p is the value stored in that integer variable. 

The pointer operator is viewed as a whole thing with its operand, so that it is regarded as a right to left associative operator. We will specifically discuss pointer soon. 

The comma operator in C++ is a binary operator that evaluates its first operand and discards the result, and then evaluates the second operand and returns this value (and type); there is a sequence point between these evaluations. It has the lowest precedence among all C++ operators. 

Here's an example of how to use it (please test in the online C++ compiler (IDE)):

#include <iostream>

using namespace std;


int main() {

   int a = 5, b = 10;

   int c = (a++, b++);

   cout << "a: " << a << endl;

   cout << "b: " << b << endl;

   cout << "c: " << c << endl;

   return 0;

}

This will output:

a: 6

b: 11

c: 10

Why?  In c = (a++, b++),  the operation sequence is equivalent to

a = a+1, then c = b++, which is equivalent to c = b, b = b+1

The comma operator is a left to right operator. 

In C++, a structure pointer is a pointer that points to the address of the memory block that stores a structure. The arrow operator (->) in C++ allows you to access elements in structures and unions. It is used with a pointer variable pointing to a structure or union. Here's an example of how to use it (please test in the online C++ compiler (IDE)):

#include <iostream>

using namespace std;


struct Person {

   string name;

   int age;

};


int main() {

   Person person = {"John", 25};

   Person *ptr = &person;

   cout << "Name: " << ptr->name << endl;

   cout << "Age: " << ptr->age << endl;

   return 0;

}

This will output:

Name: John

Age: 25

In C++, the subscript operator is used to access an element of an array. It is denoted by the square brackets ([ ]). 

Here's an example of how to use it (please test in the online C++ compiler (IDE)):

#include <iostream>

using namespace std;


int main() {

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

   cout << "arr[2]: " << arr[2] << endl;

   return 0;

}

This will output:

arr[2]: 3

It is a binary operator and has left to right associativity. 

In C++, the function call operator is used to denote a function. It is denoted by the parentheses (). 

Here's an example of how to use it (please test in the online C++ compiler (IDE)):

#include <iostream>

using namespace std;


void printHello() {

   cout << "Hello!" << endl;

}


int main() {

   printHello();

   return 0;

}

This will output:

Hello!

It is a unary operator and has left to right associativity (the only left to right in unary operators). 

g. Operator Precedence 

In C programming, operator precedence refers to the order in which operators are evaluated in an expression. It is very important in evaluate an expression's value. Operator precedence is listed in the table below:

Table 7. Operator precedence

From the above table, it is easy to see that comma operator has the lowest precedence, and postfix operators such as the function call operator, the subscript operator, the structure pointer operator, the post-increment operator, and the post-decrement operator have the highest precedence. You may come to check this table for precedence when you are using them in your expressions. 

Let's work on a lab to better understand operator precedence in C++. 

Hands-on:

Please enter the following program in the online C compiler, run and observe the results. 

#include <iostream>

using namespace std;

main() {


   int a = 20;

   int  b = 10;

   int  c = 15;

   int d = 5;

   int e;

 

   e = (a + b) * c / d;      // 30 * 15 / 5

   cout << "Value of (a + b) * c / d is : " <<  e << endl;


   e = ((a + b) * c) / d;    // (30  * 15 )  / 5

   cout << "Value of ((a + b) * c) / d is  :" << e << endl;


   e = (a + b) * (c / d);   // 30 * (15/5)

   cout << "Value of (a + b) * (c / d) is  : " <<  e << endl;


   e = a + (b * c) / d;     //  20 + 150/5

   cout << "Value of a + (b * c) / d is  : "  << e << endl;

 

   return 0;

}

If there is nothing going wrong, the result should look like:

Value of (a + b) * c / d is : 90

Value of ((a + b) * c) / d is  :90

Value of (a + b) * (c / d) is  : 90

Value of a + (b * c) / d is  : 50

You may construct more formula with various operators and observe their precedence in execution. 

4.Expressions 

In C++ programming language, an expression is anything that gives a value, such as an operand, or a combination of operand(s) and operator(s) that can be evaluated to a value. The operand can be a literal value, variable, constant, function, or another expression. The operator can be any of the operators as discussed above. 

Expressions may be categorized into a few types such as primary expressions, arithmetic expressions, logical expressions, conditional expressions, relational expressions, pointer expressions, and bitwise expressions. 

A primary expression is a building block of more complex expressions. It may be a literal value, named constant, variable, function, generic selection, keywords, or an expression in parentheses. 

A postfix expression is a primary expression followed by an operator — for example, the array subscript or postfix increment operator. For example, myArray[5] is an array element expression, a++ is an increment expression.  similarly, there are prefix expressions that have an operator before a primary expression such as ++a. These are expressions with unary operators. 

An arithmetic expression consists of arithmetic operators (+, -, *, /, %) and computes values of int, float, or double type. 

A relational expression consists of comparison operators (==, >, <, >=, <=) and computes the answer in the bool type, i.e., true (1) or false (0).

A logical expression consists of logical operators (&&, ||, !)  and combines relational expressions to compute answers in the bool type. 

A conditional expression consists of conditional statements (?:) that return true if the condition is met and false otherwise.  

Note: Generally, any expression that result in true or false is called a conditional expression. 

A pointer expression may consist of an address operator (&) and returns address values. 

A bitwise expression consists of bitwise operators (>>, <<, ~, &, |, ^) and performs operations at the bit level. 

Let's work on a lab to better understand the types of expressions. 

Hands-on:

Please enter the program below in the online C++ compiler (IDE). Run and observe the results. 

#include <iostream>

using namespace std;

int main(){


  //Arithmetic expression

  int a = (6 * 2) + 7 - 9;

  cout << "The arithmetic expression returns: " << a << endl;


  //Relational Expression

  int b = 10;

  cout << "The relational expression returns: " << (b % 2 == 0) << endl;


  //Logical Expression

  int c = (7 > 9) && ( 5 <= 9);

  cout << "The logical expression returns: " << c << endl;


  //Conditional Expression

  int d = (34 > 7) ? 1 : 0;

  cout << "The conditional expression returns: " << d << endl;


  //Pointer Expression

  int e = 20;

  int *addr = &e;

  cout << "The pointer expression returns:" << addr << endl;


  //Bitwise Expression

  int f = 10;

  int shift = 10 >> 1;

  cout << "The bitwise expression returns: " << shift << endl;


  return 0;

}

If nothing goes wrong, the output should look like:

The arithmetic expression returns: 10

The relational expression returns: 1

The logical expression returns: 0

The conditional expression returns: 1

The pointer expression returns:0x7ffd1b50210c

The bitwise expression returns: 5

You may construct your own expressions and test in a program like this one. 

5. Statements and Blocks 

A statement in a program is like a sentence in English. It is the smallest complete executable unit. A statement consists of expressions and /or keywords and ends with a semicolon (;).  

There are five basic types of statements plus their combinations to from compound statements in C++ programming language:

i. Declaration statements

ii. Expression statements

iii. Jump statements

iv. Selection statements

v. Iteration statements

vi. Compound statements

Some references may have labeled statements, which are statements with labels. 

a. Declaration statements 

In C++ programming language, a declaration statement is a statement formed from a primary expression of declaration that introduces one or more identifiers into the program and specifies their meaning and properties.

In C++ programming language, a declaration statement is used to declare a variable (include named constant) or function. The syntax of a declaration statement looks like:

type variable_name; //declare a variable

or

type variable_name = initial_value; //declare a variable with initial value

or 

type function_name(parameter_list); //declare a function prototype

In the above declaration statements, type is a data type discussed earlier. 

For example,

    int my_var = 0; //declare variable my_var with initial value 0

    int my_fun(); //declare function my_fun();

b. Expression statements 

In C++ programming language, an expression statement is a statement that consists of an expression followed by a semicolon. The execution of such a statement will get an evaluated result of the expression. Most C++ programs' statements are expression statements.  

Here are some examples of expression statements in C++: 

a = 5; // assignment statement formed from assignment expression

printf("Hello World!"); // function call statement from a function call primary expression

x++; // arithmetic (increment) statement from arithmetic expression

c. Jump statements 

In C++ programming language, a jump statement is a statement that causes the program to transfer control to another part of the program. 

The four types of jump statements in C++ are: 

It is generally considered bad practice to use goto statements because they can make code difficult to read and understand. You may simply skip this section for goto statement. The use of goto can be simply avoided by using break and continue statements. 

The goto statement in C++ is a jump statement that is used to jump from one part of the code to any other part of the code in C. It helps in altering the normal flow of the program according to our needs. The goto statement can be used to jump from anywhere to a specified place in a function.   When the C++ compiler reaches the goto statement, it will jump unconditionally (both forward and backward) to the location specified in it (we called it as a label). However, it is highly discouraged as the goto statement makes the program logic very complex and makes tracing the flow of the program very difficult. The use of goto can be simply avoided by using break and continue statements.  

The goto statement is formed from goto primary expression. For example,

#include <iostream>

using namespace std;

int main() {

   int i = 0;


   loop:  //label

      cout << i << endl;

      i++;

      if (i < 10) {

         goto loop; //goto statement

      }


   return 0;

}

In this example, the goto statement transfers control back to the beginning of the statement labeled “loop”. 

The break statement is formed from break primary expression and used to exit a loop body or switch body. For example (please test it in the online C++ compiler (IDE)

#include <iostream>

using namespace std;

int main() {

   int i;


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

      if (i == 5) {

         break;  //break statement

      }

      cout << i <<endl;

   }


   return 0;

}

In this example, the break statement is used to exit the loop when the value of “i” is equal to 5. 

The example below is usingn the break statements to exit a switch body:

switch (expression) {

   case constant1:

      // code to be executed if expression is equal to constant1;

      break;

   case constant2:

      // code to be executed if expression is equal to constant2;

      break;

   default:

      // code to be executed if expression doesn't match any of the above cases;

}

In this example, each case of the switch statement has a break statement that is used to exit the switch block once the code for the case has been executed. 

The continue statement is used to skip the current iteration of a loop and move on to the next iteration. It is formed from continue primary expression. For example (please test in the online C++ compiler (IDE):

#include <iostream>

using namespace std;

int main() {

   int i;


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

      if (i == 5) {

         continue; //continue statement

      }

      cout << i << endl;

   }


   return 0;  //return statement

}

In this example, a continue statement is to skip the loop when i is 5 and start the next cycle of the loop. 

Note:  please compare the output from this program and the one for break statement. You should see the difference between continue and break:  continue shall skip the current cycle and work on the following cycles in the loop, while break shall stop working in the loop. 

the return statement is used to return a value from a function. The return statement is formed from a return primary expression. Here is an example of a function that returns an integer value: 

int add(int x, int y) {

    int sum = x + y;

    return sum;  //return statement

}

To summarize, the goto statement is considered a harmful construct and a bad programming practice. The other three jump statements are used in loops and functions to control the flow of execution. We will see more of their usage and examples when we discuss loops and functions. 

d. Selection or conditional statements 

In C++ programming language, selection statements are based on relational and / or logical expressions  and used to control the flow of execution based on the value of an expression.

The two types of selection statements in C++ are below:

i. if statement

An if statement is a selection statement that allows for conditional execution of code based on the value of an expression. For example (please test in the online C++ compiler (IDE)),

#include <iostream>

using namespace std;

int main() {

   int x = 5;

      //the statement below is an example of if-statement

   if (x == 5) {

      cout << "x is equal to 5" << endl;

   }

   return 0;

}

As shown in the example, if statement consists of three parts:

1) the if keyword.

2) the conditional expression enclosed in a pair of parentheses.

3) the if statement body enclosed in a pair of curly brackets. When the if statement body consists of only a single statement, the curly brackets can be omitted such as 

if(x==5) cout << "x is equal to 5" << endl;

Often, the keywords if and else combine to form multiple branches or nested if statements. For example,

int x = 10;


if (x > 5) {

   cout << "x is greater than 5";

} else {

   cout << "x is less than or equal to 5";

}

In this example, if x is greater than 5, then the program will output “x is greater than 5”. Otherwise, it will output “x is less than or equal to 5”. 

ii. switch statement

In C programming language, switch statements are used to control the flow of execution based on the value of an expression. For example (please test in the online C++ compiler (IDE)),

#include <iostream>

using namespace std;

int main() {

   int x = 2;

   //Example of a switch statement

   switch (x) {

      case 1:

         cout << "x is equal to 1" << endl;

         break;

      case 2:

         cout << "x is equal to 2" << endl;

         break;

      default:

         cout << "x is not equal to 1 or 2" << endl;

   }


   return 0;

}

As shown in the example, the switch statement consists of three parts:

1) the switch keyword.

2) the conditional expression enclosed in a pair of parentheses.

3) the switch statement body enclosed in a pair of curly brackets. The switch statement body consists of one or more case branches and end with a default branch. A case branch consists of a case header and  a case body. The case header is in the form of 

case value:

it consists of keyword case and a possible value of the conditional expression in the parentheses. In this example, 1 and 2 are the possible values of x. The case header ends with colon (:).

The case body consists of a few statements, which can be any types of statements. In this example, there is only a cout statement in a case. The case body ends with a break statement, which stop continuing to execute the other branches below. 

The default branch is the last branch in the switch body, which shall be executed once no case branch meets the condition. 

The main difference between if statements and switch statements is that if statements are used when there are only two cases of a condition to check, whereas switch statements are used when there are more than two cases of a condition to check, and the condition gives a value for the cases. 

e. Iteration or looping statements 

Iteration statements in C++ are used to execute a block of code repeatedly for a specified number of times or until a condition is met. These statements also alter the control flow of the program and thus can also be classified as control statements in C++ Programming Language. There are three types of looping statements in C++: For Loop, While Loop and Do-while loop. A loop consists of three parts: conditional value initialization, test expression of condition, and increment/decrement or update the conditional value. For different types of loops, the conditional expressions might be at various places of the loop

i. For loop

The For Loop is one of the three types of looping statements in C++. It is the most commonly used loop because it has all the three parts of the loop in the one line. The syntax of a for loop look like: 

for(initialization; test expression; update expression) {

//body of loop

}

A for loop consists of three parts:

1) the keyword for.

2) the condition enclosed in a pair of parentheses.

3) the for loop body enclosed in a pair of curly brackets.

The condition consists of three parts: the initialization, the test expression, and the update expression. 

The initialization part is executed only once at the beginning of the loop. It is the entry condition to enter the loop. 

The test expression is evaluated at the beginning of each iteration. If it evaluates to true, then the body of the loop is executed. otherwise, the program execution moves on to the next statement following this for loop. 

After each iteration, the update expression is executed before evaluating the test expression again. 

The for-loop body consists of a number of other statements. When there is zero or one statement in the for loop, the curly brackets can be omitted. 

Here's an example of a for loop (please test in the online C++ compiler (IDE))

#include <iostream>

using namespace std;

int main() {

   int i;

   //for loop

   for (i = 1; i <= 5; i++) {

      cout << i << endl;

   }

   return 0;

}

This program initializes the variable i to 1, then tests whether i is less than or equal to 5. If it is, it executes the body of the loop (which prints the value of i), then increments i by 1. It repeats this process until i is no longer less than or equal to 5. 

ii. While loop

The while loop is another type of looping statement in C++. It executes the statement(s) in the loop body as long as a given condition is true. The syntax of a while loop in C looks like: 

while (condition) {

   statement(s);

}

A while loop consists of three parts:

1) the keyword while.

2) the condition enclosed in a pair of parentheses.

3) the while loop body enclosed in a pair of curly brackets.

The condition is of expression that produces a Boolean result, true or false. In C++, false is 0, true is any nonzero value. 

The while loop body, statement(s), may be a single statement or a block of statements. Below is an example of while loop (please test in the online C++ compiler (IDE)): 

#include <iostream>


int main() {

   int i = 1;

  //while loop statement

   while (i <= 5) {

      cout << i << endl;

      ++i;

   }

   return 0;

}

This program initializes the variable i to 1, then tests whether i is less than or equal to 5. If it is, it executes the body of the loop (which prints the value of i), then increments i by 1. It repeats this process until i is no longer less than or equal to 5.

iii. Do-while loop

The do-while loop is one of the three loop statements in C++. It is popularly used to traverse arrays, vectors, and some other data structures. The do-while loop is similar to the while loop but the body of do-while loop is executed at least once and then, the test expression is evaluated. The syntax of the do...while loop looks like: 

do {

   statement(s);

} while (condition);

Do-while loop consists of three parts:

1) the keyword do.

2) the loop body enclosed in the curly brackets.

3) the while condition with the keyword while and condition enclosed in a pair of parentheses. 

Please note that the conditional expression is at the end of the loop, so the statement(s) in the loop executes once before the condition is tested. 

Here's an example of a do-while loop that prompts the user to enter a number (please test in the online C++ compiler (IDE))


#include <iostream>

using namespace std;

int main() {

   double number, sum = 0.0;


   do {// The loop body is executed first 

     cout << "Enter a number: ";

      cin >> number;

      sum += number;

   } while(number != 0.0);  // The test expression is evaluated 

   cout << "Sum = " << sum << endl;

   return 0;

}

This program uses a do-while loop to prompt the user to enter a number. The loop works as long as the input number is not 0. The do-while loop executes at least once i.e. the first iteration runs without checking the condition. The condition is checked only after the first iteration has been executed.

f. Compound statements 

A compound statement is a group of statements that are enclosed in curly braces `{}`. It is used where multiple statements are required. The compound statement is treated as a single statement by the compiler. The syntax of a compound statement is:

{

   statement1;

   statement2;

   .

   .

   .

   statementN;

}

That is, a group of statements enclosed in a pair of curly brackets. Here, statement1, statement2, ..., statementN are any valid C++ statements as discussed above. The compound statements can be nested in another compound statements. 

The compound statements are usually used as a structure body, function body, loop body, selection statement body, and so on. 

g. Blocks

A block in C++ is a set of statements written within a pair of curly braces ({}). A block may contain other blocks within itself, that is, nested blocks. A variable declared inside a block has a block scope and is accessible inside the block and its inner blocks. 

A compound statement is actually a block. 

6. Arrays 

An array in C++ is a collection of similar data items stored in contiguous memory locations. The data items in an array can be of primitive data types such as int, char, float, etc., and also derived and user-defined data types such as pointers, structures, and so on. The elements of an array are accessed by their index number.  The index number starts from 0 and goes up to (size of the array - 1). The size of an array must be specified at the time of declaration.

Arrays are used in C++ for a variety of reasons. They are used to store a collection of similar data items. They are also used to store the collection of derived and user-defined data types such as pointers, structures, etc. Arrays are also used to pass a large number of arguments to functions. They are also used to implement other data structures such as stacks, queues, and trees.

The syntax of declaring an array in C++ is:

Type arrayName[arraySize];

Here,  the Type is the type of data that the array will hold. arrayName is the name of the array, and arraySize is the number of elements that the array can hold. For example, 

int numbers[5];

This declares an array named numbers that can hold 5 integers. 

Once an array is declared, its elements  are accessed by their index numbers. The index number starts from 0 and goes up to (size of the array - 1). For example,

int numbers[7] = {1, 2, 3, 4, 5, 6, 7};// An array of 7 int items is declared and initialized 

cout << numbers[2] << endl;

This prints the third element of the array numbers, which is `3`.

We can easily loop through an array with a for loop. For example, 

int numbers[7] = {1, 2, 3, 4, 5, 6, 7};

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

   cout << numbers[i] << endl;

}

This prints all the elements of the array numbers. 

Arrays are popularly used in processing a group of same type of data. For example, we want to sum up a group of integers, we can use array to easily implement it. 

#include <iostream>

using namespace std;

int main() {

  int numbers[7] = {1, 2, 3, 4, 5, 6, 7};

  int sum = 0;

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

    sum += numbers[i];

  }

  cout << "The sum of the array is " << sum;

}

This program creates an array of integers called numbers with five elements and initializes them with values from 1 to 7. It then uses a for loop to iterate over the array and add up all the values. Finally, it prints out the sum of the array. 

In C++ programming, we can create an array of arrays. These arrays are known as multidimensional arrays. For example, 

float x[3][4];

Here, x is a two-dimensional (2d) array. The array can hold 12 elements. You can think the array as a table with 3 rows and each row has 4 columns.

To access an element from the multidimensional array, add the index for the element you want. For example, x[1][2] will access the element at row 1 and column 2 of the array. You can also use a for loop or for each loop to access multiple elements in a multidimensional array.

We can use a nested for loops (one for loop inside another for loop) to access elements of a multidimensional array in C++. Here is an example of how to use a for loop to initialize each member of a 2D array one by one:

int x[3][4];

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

  for (int j = 0; j < 4; j++) {

    x [i] [j] = i + j;

  }

}

This method is useful when the value of each element has some sequential relation. 

7. Strings 

Strings are used in C++ programming language to represent text such as words and sentences. They are also used to manipulate text data. For example, you can use strings to store user input or read data from a file. 

In C++ programming language, a string variable contains a collection of characters surrounded by double quotes. To create and use strings, you must include the header file <string>, and declare a string like:

#include <string>  //include the string library header file

string name = "John Doe"; //Create a string variable with initial value

C++ allows you to concatenate strings with the plus '+' operator. For example (please test it in the online C++ compiler (IDE))

#include <iostream>

#include <string>

using namespace std;

int main() {

    string firstName = "John";

    string lastName = "Doe";

    string fullName = firstName + " " + lastName;

    cout << fullName << endl;

    return 0;

}

This program declares two string variables named firstName and lastName, concatenates them using the + operator, and stores the result in a third string variable named fullName. It then prints the full name to the console. 

The + operator is overloaded to automatically identify numbers and strings. If you add two numbers, the result will be a number. If you add two strings, the result will be a string concatenation as the above example shows. If you add a number to a string, however, an error occurs. For example (please test it in the online C++ compiler (IDE)

#include <iostream>

#include <string>

using namespace std;

int main() {

    string x = "10";

    int y = 20;

    string z = x + y;

    cout << z << endl;

    return 0;

}

This program declares a string type variable x and an int type variable y, then tries to "add" up them and assign the result to variable z. Since x is string, though it contains numeric chars, it cannot be added to int y. If you try to compile (or Run) it, you shall receive an error like "no match for operator +". 

C++ allows you to easily obtain the length of a string by using the length() function, or size(), which is an alias of length(). For example (please test it in the online C++ compiler (IDE))

#include <iostream>

#include <string>

using namespace std;


int main() {

  string txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

  cout << "The length of the txt string is: " << txt.length();

  return 0;

}

The result should be displaying "The length of the txt string is: 26". You may use txt.size() to replace txt.length(). 

Since a string is essentially an array of characters, C++ allows you to access the characters in a string by referring to its index number inside square brackets [ ]. For example, 

string myString = "Hello";

cout << myString[0]; // Outputs H

Note: The subscription of an array starts with 0. 

You can update a character in a string by assigning a char to a position. For example, 

string myString = "Hello";

myString[0] = 'J';

cout << myString; // Outputs Jello instead of Hello

C++ allows you to easily input a string to a string variable by using the extraction operator >> on cin. For example:

string name;

cout << "Type your first name: ";

cin >> name; // get user input from the keyboard

cout << "Your name is: " << name;

Note: cin considers a space (whitespace, tabs, etc) as a terminating character, which means that it can only store a single word (even if you type many words). Therefore, the above code accepts only one word and assigns it to string variable name. If you enter two words separated by a space, only the first word will be accepted and assigned to variable name. 

Tip: because of the issue caused from cin, C++ provides function getline() to read a line of text. It takes cin as the first parameter, and the string variable as the second. For example (please test it in the online C++ compiler (IDE)),

#include <iostream>

#include <string>

using namespace std;


int main() {

  string fullName;

  cout << "Type your full name: ";

  getline (cin, fullName);

  cout << "Your name is: " << fullName;

  return 0;

}

Tip: Even though getline() allows us to accept a whole line of a string to be stored, it does not identify each of the words in the input string. To recognize each word in the input string, we may use C++ istringstream class, which is used to read input from a string as if it were a stream, and is often used to extract values from a string. istringstream is defined in <sstream> so that we should include this header file to use istringstream. For example (please test it in the online C++ compiler (IDE)),

#include <iostream>

#include <string>

#include <sstream>


using namespace std;


int main() {

  string fullName;

  cout << "Type your full name: ";

  getline(cin, fullName);

  cout << "Your name is: " << fullName << endl;

 

  istringstream iss(fullName);

  string word;

  cout << "To display each single name: " << endl;

  while(iss >> word){

      cout << word << endl;

  }

 

  return 0;

}

In execution of this program, if we enter multiple words in a string, each of the words will be accessed and displayed. A sample execution looks like:

Type your full name: John Michael Doe

Your name is: John Michael Doe

To display each single name: 

John

Michael

Doe

A few characters have special meaning and may cause issues if they are used as normal characters. For example, double quote (") cannot be directly enclosed in a pair of double quotes as a normal character in a string. To reach the goal of using double quote as a normal character, we must use the backslash (\), which is called the escape character, to turns it into a normal character. This kind of characters include single quote ('), double quote ("), and backslash (\). For examples, 

string txt = "It is the so-called \"Baozi\" in the country.";  

string txt = "It\'s alright.";

string txt = "The character \\ is called backslash.";

A few other characters, when used with the escape character, will change their original meaning such as slash n (\n) is newline, slash r (\r) is carriage return, and slash t (\t) works as a tab. To summarize, let's use them in an example (please test it in the online C++ compiler (IDE)):

#include <iostream>

#include <string>

#include <sstream>


using namespace std;


int main() {

  cout << "It is the so-called \"Baozi\" in the country." << endl;  

  cout << "It\'s alright." << endl;

  cout << "The character \\ is called backslash." << endl;

  cout << "This line is ended by a new line character \n" << endl;

  cout << "Carriage return is \r" << endl;

  cout << "Slash t add a tab \t in the string." <<endl;

 

  return 0;

}


The output should looks like

It is the so-called "Baozi" in the country.

It's alright.

The character \ is called backslash.

This line is ended by a new line character 


Carriage return is 


Slash t add a tab in the string.

Please observe the output and compare against the strings in the program code, and be sure to understand the meaning of these special characters and the use of the escape character (\). 

8. Math's 

The advantages of math processing in C++ include the ability to perform complex mathematical calculations and operations quickly and accurately. This is especially useful in scientific and engineering applications where precise calculations are required. 

Besides arithmetic operators such as +, -, *, /%, ++, --, etc. to perform basic math operations, C++ provides a lot of functions in a few library header files.  

The <cstdlib> header file in C++ provides a set of general-purpose functions. It also declares several mathematical functions such as abs() to find the absolute value of a number. 

The <cmath> header file in C++ declares a set of functions to compute common mathematical operations and transformations such as trigonometric functions, exponential and logarithmic functions, rounding and remainder functions, power functions, error and gamma functions, minimum, maximum and difference functions and other functions. The header file also declares a set of macros/functions such as fpclassify to classify floating-point value.

The table below shows some math functions defined in <cstdlib> and <cmath>. More details can be found at Common mathematical functions - cppreference.com

Table 8. Common C++ Math Functions (cppreference.com)

Here is an example of using math functions in C++:

#include <iostream>

#include <cmath>


using namespace std;


int main() {

    double x = 2.0;

    double y = 3.0;


    cout << "The square root of " << x << " is " << sqrt(x) << endl;

    cout << "The value of e raised to " << y << " is " << exp(y) << endl;

    cout << "The value of log(" << x << ") is " << log(x) << endl;

    cout << "The value of pow(" << x << ", " << y << ") is " << pow(x, y) << endl;


    return 0;

}

This program uses the <cmath> header file to calculate the square root of a number, the value of e raised to a number, the natural logarithm of a number and the power of a number. 

9. Input/Output 

C++ uses a convenient abstraction called streams to perform input and output operations in sequential media such as the screen, the keyboard or a file. A stream is an entity where a program can either insert or extract characters to/from. There is no need to know details about the media associated with the stream or any of its internal specifications. All we need to know is that streams are a source/destination of characters, and that these characters are provided/accepted sequentially (i.e., one after another). The standard library <iostream> defines a handful of stream objects that can be used to access what are considered the standard sources and destinations of characters by the environment where the program runs (cplusplus.com/doc/tutorial/basic_io/): 

For example,

cin >> firstName; //input a string for string variable firstName

cout << firstName; //output a string

Since they perform stream operations, they can work with multiple insertion operators or extraction operators chained in a single statement. For example,

cin >> firstName >> lastName; //input two separate strings for firstName and lastName

cout << "The first name is: " << firstName << ", and the last namem is: " << lastName; //output multiple string

cin and cout work with not only strings, but also with char, int, float, double, etc. For example, suppose age is an int variable, we may have input and output statements like

cin >> age; //input an integer for int variable age

cout << "My age is: " << age; //output a streams mixed with a string and an integer

cout does not automatically break a line. To break a line, we may use new line character "\n" in a string such as 

cout << "My age is: \n" << age;

This statement will force age to be displayed on a new line. "\n" force the following output to start with a new line.  C++ provides an output mainpulator, endl, to insert a newline character into the output sequence and do the same thing as "\n". For example, the above statement can be written as 

cout << "My age is: " << endl << age;

Generally, we use endl at the end of an output statement, and keep using "\n" inside the output sequence. For example,

  cout << "My age is: \n" << age << endl;

cerr is used to output errors immediately without buffering them. It is an object of the ostream class similar to cout. clog is used to output errors after buffering them. It is also an object of the ostream class similar to cout. clog is commonly used for logging purposes. For non-critical event logging, efficiency is more important so clog is preferred to cerr.  Here's an example of how to use cerr and clog in C++ (please test in the online C++ compiler (IDE):

#include <iostream>

using namespace std;


int main() {

    int x = 10;

    cerr << "Error occurred: " << x << endl;

    clog << "Logging information: " << x << endl;

    return 0;

}

The iomanip library is a library in C++ which helps us in manipulating the output of any C++ program. There are many functions in this library that help in manipulating the output. To name a few we have functions to reset flags, set fill characters, set precision, get date and time, etc. It is a part of input-output library of the C++ standard library.

Here are some examples of manipulators in C++:

#include <iostream>

#include <iomanip>

using namespace std;


int main() {

    int x = 10;

    cout << "The value of x is: " << setw(5) << x << endl;

    cout << "The value of x is: " << setfill('0') << setw(5) << x << endl;

    cout << "The value of pi is: " << setprecision(3) << 3.14159 << endl;

    return 0;

}

This program shall output

The value of x is:    10

The value of x is: 00010

The value of pi is: 3.14

Manipulation function setw(int) changes the width of the next input/output field. If there is no enough digits to fill the width, it produces spaces to fill up the width. 

Manipulation function setfill(char) changes the fill character. In the example above, it changes the default spaces to 0s to fill up the width of displaying x. 

Manipulation function setprecision(int) sets decimal precision in displaying. The example above shows that it sets decimal precision to three digits, so that the given value with six digits was truncated. 

More functions and details about input/output manipulators can be found at cplusplus.com/reference/iomanip/ and Input/output manipulators - cppreference.com

In C++, there are several libraries that can be used to create Graphical User Interfaces (GUIs). Some of the most popular ones are:

Each of these libraries has its own strengths and weaknesses. For example, Qt is known for its ease of use and cross-platform compatibility, while wxWidgets is known for its native look and feel on different platforms. If you are interested in creating GUIs in C++, you have to learn these libraries. However, GUIs are not the focus of C++, and most of the time we can run C++ programs in the background, and display in other GUI interfaces such web browsers. 

10. Control Structures 

In programming, control structures are used to specify the flow of control in a program. They are used to analyze and choose in which direction a program flows based on certain parameters or conditions. There are three fundamental types of flow of control, or logic, known as: 

In C++ programming language, sequential flow is the default flow of execution. The program executes one statement after another in their order as in the source code of a program. 

Conditional flow and repetitive flow change the default sequential flow in a program. 

C++ provides three main control structures to implement the conditional flow and the repetitive flow: decision-making (or selective, or conditional) control structure, looping (or repetitive) control structure, and unconditional control structure. 

Decision-making control structure allows you to execute one set of statements when an expression is true and another set of statements when the expression is false. This control structure implements conditional flow using conditional statements such as if, if-else, nested if-else, and switch statements. 

The if statement is used to execute a statement or block only if a condition is fulfilled. Its form is:

if (condition) {

    statement(s);

}

The if-else statement two branches, one for false expression and the other for true expression. Its form is:

if (condition) {

    true_statement(s);

} else {

    false_statement(s);

}

The switch statement selects one of multiple blocks of code to execute. Its form is:

switch (expression) {

    case constant1:

        statement1;

        break;

    case constant2:

        statement2;

        break;

    default:

        default_statement;

}

The conditional operator is a simplified if-else statement. Its form is:

(condition) ? true_expression : false_expression;

Here is an example of if-else statement in C++ (please test it in the online C++ compiler (IDE):

#include <iostream>

using namespace std;


int main() {

    int x = 10;

    if (x == 10) {

        cout << "x is 10" << endl;

    } else {

        cout << "x is not 10" << endl;

    }

    return 0;

}

You can refer to selection or conditional statements

Looping control structure allows you to execute a set of statements repeatedly while a condition is true. This control structure implements repetitive flow using looping statements such as for loop, while loop and do-while loop. The for loop is used when we know the number of times we want to execute the loop. The while loop is used when we don't know the number of times we want to execute the loop. The do-while loop is similar to the while loop, but it executes at least once even if the condition is false. 

Here's an example of a for loop that prints the numbers from 1 to 10:

for (int i = 1; i <= 10; ++i) {

    cout << i << " ";

}

This loop will execute 10 times because the condition `i <= 10` is true for 10 iterations.

A for loop can be nested in another loop. For example (please test it in the the online C++ compiler (IDE)),

#include <iostream>


using namespace std;


int main(int argc, char *argv[]) {

    for (int i = 1; i <= 10; ++i) {

        for (int j = 1; j <= 10; ++j) {

            cout << i * j << "\t";

        }

        cout << endl;

    }

}

This program has a nested for loop that shall print a table looks like

1 2 3 4 5 6 7 8 9 10

2 4 6 8 10 12 14 16 18 20

3 6 9 12 15 18 21 24 27 30

4 8 12 16 20 24 28 32 36 40

5 10 15 20 25 30 35 40 45 50

6 12 18 24 30 36 42 48 54 60

7 14 21 28 35 42 49 56 63 70

8 16 24 32 40 48 56 64 72 80

9 18 27 36 45 54 63 72 81 90

10 20 30 40 50 60 70 80 90 100

Rewrite the above examples of for loop with while loop, the program that prints 10 numbers shall be 

int i = 10;  //initialize the counter

while(i <= 10) { //condition

    cout << i << " ";

i++; //update the counter

}

The program that prints a 10x10 tables with while loop shall be 

int i = 1;  //initialize the outer counter

while (i <= 10) { //check the outer condition

    int j = 1; //initialize the inner counter

    while (j <= 10) { //check the inner condition

        cout << i * j << "\t";

        ++j; //update the inner counter

    }

    cout << endl;

    ++i; //update the outer counter

}

Use do-while loop to implement the above programs, the one that prints 10 numbers shall look like

int i = 0; //initialize the counter

do {

    cout << i << " ";

    ++i;  //update the counter

} while (i < 10);  //check the condition

The program that displays a table shall look like (please test it in the the online C++ compiler (IDE):

#include <iostream>


using namespace std;


int main(int argc, char *argv[]) {

    int i = 1; //initialize the outer counter

    do {

        int j = 1; //initialize the inner counter

        do {

            cout << i * j << "\t";

            ++j; //update the inner counter

        } while (j <= 10); //check the inner counter

        cout << endl;

        ++i;  //update the outer counter

    } while (i <= 10); //check the outer counter

}

Unconditional control structure allows you to jump to another part of the program without any conditions. There are two types of unconditional control structures in C++: break and continue. 

The break statement exits a loop or switch statement. When the break statement is encountered inside a loop or switch statement, the program jumps to the next statement after the loop or switch.

The continue statement is used to skip the current iteration of a loop and move on to the next iteration. When the continue statement is encountered inside a loop, the program skips the rest of the statements in the current iteration and moves on to the next iteration.

Here’s an example of a for loop that uses both break and continue statements:

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

    if (i == 5) {

        break; // exit the loop when i == 5

    }

    if (i == 3) {

        continue; // skip this iteration when i == 3

    }

    cout << i << " ";

}

The output of this loop shall be 

0 1 2 4

because 3 is skipped, and 5 stopped further execution of the loop. 

You can refer to looping statements

11. Pointers 

In C++ programming language, a pointer is a variable that stores the memory address of another variable. Pointers are used to manipulate data using the address of the data rather than the data itself. Pointers can be used for a variety of purposes such as:

A pointer is declared using the * operator:

int *ptr;

This declares a pointer variable called ptr that can point to an integer value. 

To use the pointer, you can assign it the address of another variable using the & operator. Here is an example: 

int var = 5;

int *ptr = &var;

This assigns the address of var to the pointer variable ptr. You can then use the pointer to access the value stored in var using the * operator. Here is an example: 

int var = 5;

int *ptr = &var;

cout << *ptr << " is at memory address " << ptr << endl;

This prints 

5 is at memory address 0x7ffdee4aab34

The pointer variable ptr holds the address of var, and the dereference operator (*) is used to access the value of var through the pointer ptr.

12. Memory Handling 

Memory handling in C++ refers to the management of memory resources during program execution. C++ provides two operators for memory management: new and delete.

The new operator is used to allocate memory dynamically during runtime. It returns the first byte of the allocated memory block to a pointer variable. The syntax for using the new operator is:

pointerVariable = new dataType;

The delete operator is used to release the allocated memory for future use or for other programs to use it. It frees up the memory so that it can be used by other parts of the program. The syntax for using the delete operator is:

delete pointerVariable;

Here's an example of how to use new and delete operators in C++:

int *ptr = new int; // allocate memory for an integer variable

*ptr = 5; // assign a value to the variable

cout << *ptr << endl; // print the value of the variable

delete ptr; // deallocate the memory

This code dynamically allocates memory for an integer variable using the new operator. It assigns a value to the variable and prints its value. Finally, it deallocates the memory using the delete operator. 

Hands-on:

Please enter the program below in the online C++ compiler (IDE)

#include <iostream>

using namespace std;


int main() {

   int *ptr = new int;

   *ptr = 5;

   cout << *ptr << endl;

   delete ptr;

   return 0;

}

The execution output should be 

5

In this example, we allocate memory for an integer using the new operator. We then assign the value 5 to the integer using the dereference operator. Finally, we free the memory using the delete operator. 

13. Files

When a program is in execution, data is loaded in memory. When the program is terminated, data in memory will be lost. In order to preserve data even after the program is terminated, the data can be stored in a file.  A file is a collection of related data that is stored in a secondary storage device such as a hard drive, CD/DVD, SSD, Jump drive, and so on.  

To work with files in C++, you need to include the <fstream> header file and <iostream>. There are three classes included in the fstream library that are used to create, write or read files:

Here's an example of how to create and write to a file in C++:

#include <iostream>

#include <fstream>

using namespace std;


int main() {

    // Create and open a text file named filename.txt

    ofstream MyFile("filename.txt");


    // Write to the file

    MyFile << "Files can be tricky, but it is fun enough!";


    // Close the file

    MyFile.close();

}

This code creates a text file named `filename.txt` and writes the string `"Files can be tricky, but it is fun enough!"` to the file.

Note: to test this program, you might have to install and C++ programming IDE on your computer, because the online C++ IDE might not know the path to file on your local computer.

To read from a file, use either the ifstream or fstream class, and the name of the file.

Note that we also use a while loop together with the getline() function (which belongs to the ifstream class) to read the file line by line, and to print the content of the file:

// Create a text string, which is used to output the text file

string myText;


// Read from the text file

ifstream MyReadFile("filename.txt");


// Use a while loop together with the getline() function to read the file line by line

while(getline(MyReadFile, myText)) {

  // Output the text from the file

  cout << myText;

}


// Close the file

MyReadFile.close();

From the perspective of how a file content is stored, there are text files and binary files.  A text file contains data in the form of ASCII characters and is generally used to store a stream of characters. Text files are used to store data that humans can read. A binary file contains data in binary form (i.e. 0’s and 1’s) instead of ASCII characters. They contain data that is stored in a similar manner to how it is stored in the main memory. The binary files can be created only from within a program and their contents can only be read by a program, such as images, audio files, and executable programs. 

From the perspective of how a file content is read/write, there are sequential access and random access. With sequential access, you have to loop through the file or stream from the start like a big tape. With random access, you can read or write to any part of the file or stream. Random access is achieved by manipulating the `seekg()`, `seekp()`, `tellg()`, and `tellp()` functions. Here's an example of how to use the seekg() function to move the file pointer to a specific position in a file:

ifstream file("example.txt");

file.seekg(5); // move the file pointer to the 5th byte in the file

Here is an example of C++ program that read and display characters at specific locations in a file. 

#include <fstream>

#include <iostream>

#include <string>

using namespace std;

int main() {

    ifstream inf{"Sample.txt"};


    if (!inf) {

        cerr << "Uh oh, Sample.txt could not be opened for reading!\n";

        return 1;

    }


    string strData;


    inf.seekg(5); // move to 5th character

    getline(inf, strData);

    cout << strData << '\n';


    inf.seekg(8, ios::cur); // move 8 more bytes into file

    getline(inf, strData);

    cout << strData << '\n';


    inf.seekg(-14, ios::end); // move 14 bytes before end of file

    getline(inf, strData);

    cout << strData << '\n';


    return 0;

}

Note: to test this program, you might have to install and C++ programming IDE on your computer, because the online C++ IDE might not know the path to file on your local computer.

14. Functions 

Functions in C++ are self-contained blocks of code that perform a specific task. They are application of "divide and conquer" technique in programming that break down a large program into smaller and more manageable pieces. They make the code more modular and easier to read and maintain. Functions can also be reused in different parts of the program or in different programs altogether. 

a. The syntax of function definition

The syntax of a function definition in C++ is as follows:

type function_name(parameter list) {

   // function body

}

Here is what each part means:

Here is an example of a function in C++ (please test it in the the online C++ compiler (IDE)):

#include <iostream>

using namespace std;


//defining function add()

int add(int a, int b) {

    return a + b;

}


int main() {

    int sum = add(3, 5); //call the user defined function add(), assign its value to sum.

    cout << "The sum is " << sum << endl;

    return 0;

}

This program defines a function called add() that takes two int parameters: a and b. The function body consists of a single statement that returns the result of a plus b. The function is then called from the main() function with arguments 3 and 5 to be passed to the function's parameters a and b respectively, and the function's result (3 plus 5) is assigned to variable sum. 

Here is an example of a void function in C (please test it in the the online C++ compiler (IDE)):

#include <iostream>

using namespace std;

void add(int i, int j) //this function does not return a value, so it is void

{

   cout << i << " + " << j << " = " << i + j << endl;

}

int main()

 {

     int i,j;

     i = 1;

     j=2;

     add( i, j); //call the function add(). Since it is void, it cannot be assigned to a variable

     return 0;

 }

This function add()takes two integer parameters i and j and returns nothing. It simply prints the sum of the two integers passed to it. The main() function calls the add() function with two arguments 1 and 2 passed to add().  

b. Function prototype 

In C++, a function prototype is a declaration of a function that specifies the function's name and type signature (arity and types of arguments) but omits the function body.  The purpose of a function prototype is to provide the compiler with information about the function so that it can perform type checking and ensure that the function is being called correctly.

The syntax of function prototype in C++ is as follows: 

type function_name(type1 parameter1, type2 parameter2, ...);

Here, type is the data type of the value returned by the function. function_name is the name of the function. type1, type 2 and so on are the data types of the parameters of the function. If there is no parameter, then it is empty inside the pair of the parenthesis. If there are multiple arguments, then they are separated by commas.  The semicolon at the end of the prototype is required.

A function prototype is used to tell the compiler about the existence of a function before it is actually defined. This is useful when a program calls a function before its definition. The prototype serves as an agreement between the caller and the callee about what the function will do and what arguments it will take, helps in detecting errors at compile-time rather than at runtime. Using function prototype allows declaration of functions being placed in header files, so that they can be compiled separately from programs and be called by programs as a library. 

Here is an example of using function prototype in C++ (please test it in the the online C++ compiler (IDE)):

#include <iostream>

using namespace std;

// Function prototype

int add(int x, int y);


int main() {

    int a = 10;

    int b = 20;

    int sum = add(a, b);

    cout << "The sum of " << a << " and " << b << " is " << sum << endl;

    return 0;

}


// Function definition

int add(int x, int y) {

    return x + y;

}

This program should output 

The sum of 10 and 20 is 30

In this example, we have declared a function prototype for the add() function before the main() function. The prototype tells the compiler that the add() function takes two integer arguments and returns an integer value. The actual definition of the add() function comes after the main() function.

In this example, if the function prototype is missed, the compiler shall return an error message like:

error: 'add' was not declared in this scope

c. Pass by value vs. pass by reference

When a function is called, arguments that have actual values shall be passed to replace the function's parameters. 

Note: an argument is a value that is passed to a function when the function is called, while a parameter is a variable in the declaration of a function. The parameter is used to receive the argument that are passed during a function call. An argument is also called an actual parameter because it has actual value. A parameter is also called a formal parameter because it indicates the data type and position in the parameter list but has no actual value. 

In C++, when you pass an argument to a function, you can either pass it by value or by reference. 

Pass by value means that the function receives a copy of the argument’s value. Any changes made to the parameter inside the function have no effect on the original argument.

Pass by reference means that the function receives a reference to the original argument, rather than a copy. Any changes made to the parameter inside the function shall affect the original argument. 

In C++, pass by value is used by default. To pass an argument by reference, you need to use the address operator.

Here’s an example that demonstrates the difference between pass by value and pass by reference (please test it in the the online C++ compiler (IDE): 

#include <iostream>

using namespace std;

void passByValue(int x) {

    x = 10;

}

void passByReference(int &x) { //the address operator & indicates that this parameter is a reference

    x = 10;

}


int main() {

    int a = 5;

    int b = 5;


    cout << "Before pass by value: " << a << '\n';

    passByValue(a);

    cout << "After pass by value: " << a << '\n';


    cout << "Before pass by reference: " << b << '\n';

    passByReference(b);

    cout << "After pass by reference: " << b << '\n';


    return 0;

}


This program will output 

Before pass by value: 5

After pass by value: 5

Before pass by reference: 5

After pass by reference: 10

In this example, we have two functions: passByValue() and passByReference(). The passByValue() function takes an int parameter x and sets its value to 10. The passByReference() function takes an int reference parameter x and also sets its value to 10.

In the main function, we have two variables a and b, both initialized to 5. We then call the passByValue() function with a as an argument, and the passByReference() function with b as an argument.

After calling the passByValue() function, the value of a is still 5, because the function received a copy of a, rather than a reference to it. However, after calling the passByReference() function, the value of b has changed to 10, because the function received a reference to b, and was able to modify its value directly.

d. Recursions 

Recursion is a technique in C++ programming language where a function calls itself repeatedly until a certain condition is met. A function that calls itself is called as a recursive function and the technique is called as recursion. 

In C++, a recursive function is defined in the same way as any other function, but with one key difference: somewhere within the function body, the function calls itself. Each time the function is called, it performs some part of the overall task and then calls itself again with a new set of inputs. This process continues until some base case is reached, at which point the function returns a value without making any further recursive calls.

Here's an example of a simple recursive function in C++ that calculates the factorial of a non-negative integer:

#include <iostream>

using namespace std;

int factorial(int n) {

    if (n == 0) {

        return 1;

    } else {

        return n * factorial(n - 1);

    }

}


int main() {

    int result = factorial(5);

    cout << "5! = " << result << '\n';


    return 0;

}

In this example, the `factorial()` function takes an `int` parameter `n` and returns the factorial of `n`. The function uses an `if` statement to check whether `n` is equal to `0`. If it is, the function returns `1` (the base case). Otherwise, the function returns `n` multiplied by the result of calling itself with `n - 1` as an argument (the recursive case).

Recursion can be a powerful tool for solving complex problems, but it's important to use it carefully. Recursive functions can consume a lot of memory and processing power if not designed properly, and it can be easy to create infinite loops if the base case is not defined correctly.

Advantages:

Disadvantages:

15. Classes and Objects

C++ is usually considered a superset of C, meaning that any valid C program is also a valid C++ program. However, C++ provides additional features and capabilities that are not available in C, such as support for object-oriented programming, templates, and exception handling.

a. Object-Oriented Programming

Traditionally, a system is viewed as one single object, and programming is to simulate the system as a process to solve problems that was based on input to produce output; hence programming is said being based on the IPO (input-process-output) model. To better organize the code, high-level programming languages promoted Structured Programming (SP) that organizes code in modules (so-called modular programming) based on three basic flows of control - sequential, selective, and repetitive. The methods are defining modules as procedures or functions, so structured programming is also called procedural programming

Later, a more advanced programming methodology called Object-Oriented Programming (OOP) was developed. OOP views a system as many related objects. Why bother? It is because when a system is large and complex, it becomes more challenging or even impossible for SP to solve the problem. We apply the divide-and-conquer technique to divide the large system into small and complex system into simple ones, so that we can solve the problems of large and complex systems more effectively. 

OOP starts to divide a system into objects and find their relationships. Once objects are found, OOP categorize the objects into classes. So, the main tasks in OOP are figuring out objects and their relationships and designing classes.  An object is an instance of a class, and a class is a type (abstraction) of objects. 

An object (and so a class) consists of attributes (or properties) that describe the object states and methods (or member functions) that describe the object operations. 

For example, based on many dogs' common features, we may design a Dog class that has attributes (or properties) such as Name, Age, Breed, and Shot status. Three dog objects, as shown in the figure below, have their specific values of Name, Age, Breed, and Shot status. These values help us identify them one from the others.  We may add member functions in the class design, such as bark(), jump(), eat(), and so on.  

Note: the figure below shows the Dog class definition and three Dog instances. No member function is shown. 

Figure.  Dog class definition and some objects created from the dog class

Some of the common relationships between objects include:

Association: An association is a structural relationship that indicates that objects of one class are connected and can navigate to objects of another class.

Aggregation: Aggregation is a special form of association where the relationship between two objects is a "has-a" or "whole-part" relationship. For example, a car has an engine, so the relationship between the car object and the engine object is an aggregation.

Composition: Composition is a stronger form of aggregation where the lifetime of the part is tied to the lifetime of the whole. For example, a human has a heart, so the relationship between the human object and the heart object is a composition.

Inheritance: Inheritance is a way to reuse code by creating new classes that inherit properties and methods from existing classes.

These relationships can be used to model real-world problems and improve code reusability and extensibility.

As a programming paradigm, OOP focuses on the use of objects to represent and manipulate data. There are several key concepts in OOP that enable developers to write code that is modular, reusable, and maintainable. These concepts include:

C++ as a programming language provides the capability to implement all features in OOP. However, to be compatible with C's heritage, C++ allows the use of global variables and functions, which goes against the principles of data encapsulation and abstraction in OOP. These are some reasons why C++ is classified as a partial object-oriented programming language.

b. C++ Class 

A class in C++ programming language is a user-defined type or data structure declared with the keyword `class` that contains data and functions (also called member variables and member functions) as its members, and their access is controlled by the three access specifiers: `private`, `protected`, or `public`. Classes can be considered as an expanded concept of data structures: they are like data structures that contain data members, but they can also contain functions as members. A class is like a blueprint for objects.

Here is a template for defining a class in C++:

class ClassName {

    public:  // Access specifier

        // Data members

        // Member functions

    protected:    // Access specifier

         //Data members

         //Member functions

    private:    //Access specifier

        // Data members

  //Member functions

};

In this template, we define a class called `ClassName` using the `class` keyword. Inside the class, we can define data members and functions under three specifiers: `public`, 'protected', and `private`. All members under the access specifier 'public' can be accessed from anywhere in the program, all members under the access specifier 'private' cannot be accessed from outside the class, and all members under the access specifier 'protected" can be accessed from outside the class, but only in inherited classes. 

Note: by default, the class members are private, so if the access specifier (visibility) labels are missing, then by default all the class members are private.

A class may have special member functions called constructors. A constructor in C++ is a special member function of a class that is used to initialize objects of its class type. It is automatically called at the time an object of the class is created. The constructor has the same name as the class and does not have a return type.

Here is an example that demonstrates how to define constructors in C++:

class Person {

public:

    // Default constructor

    Person() : name("Unknown"), age(0) {}

    // Parameterized constructor

    Person(const std::string& name, int age) : name(name), age(age) {}

    void introduce() const {

        std::cout << "Hello, my name is " << name << " and I am " << age << " years old." << std::endl;

    }

private:

    std::string name;

    int age;

};

In this example, we define a `Person` class with two constructors: a default constructor that takes no arguments and initializes the `name` and `age` data members to default values, and a parameterized constructor that takes two arguments and initializes the `name` and `age` data members with the provided values.

Note:

Similarly, a class may have destructors. A destructor is a special member function of a class that is executed whenever an object of its class goes out of scope or is explicitly deleted. The purpose of the destructor is to release any resources that the object may have acquired during its lifetime.

The name of the destructor is the same as the name of the class, but it is preceded by a tilde (~) symbol. A destructor takes no arguments and has no return value. Here is an example that demonstrates how to define and use a destructor in C++:

#include <iostream>


class MyClass {

public:

        //constructor

MyClass() { std::cout << "MyClass constructed" << std::endl; }


//destructor

     ~MyClass() { std::cout << "MyClass destructed" << std::endl; }

};


int main() {

    MyClass obj;

}

In this example, we define a `MyClass` class with a constructor and a destructor. The constructor prints a message when it is called, and the destructor prints a message when it is called. In the `main()` function, we create an object of `MyClass` named `obj`. When the `obj` object goes out of scope at the end of the `main` function, its destructor is automatically called, and the message "MyClass destructed" is printed.

Note: If you do not explicitly define a destructor for a class, the compiler will automatically generate a default destructor for you. This implicitly declared default destructor is an inline public member of its class. 

There are many different coding conventions and styles when it comes to defining classes in C++. Some of the common conventions include the order of access specifiers (public, protected, private), the placement of constructors (a member function to initialize the attributes) and destructors (a member function to release memory used by the class), and the separation of data members from member functions. However, these conventions can vary from company to company, team to team, or even from project to project. Many companies have their own coding standards that dictate how to name variables, classes, and functions, as well as where to place braces and how to name header files in relation to the source files. For example, Google has its own C++ Style Guide that outlines the conventions that govern their C++ code. It's important to follow a consistent coding style within a project or team to make the code more readable and maintainable. 

Here is an example of defining a class in C++ (please test it in the the online C++ compiler (IDE)):

#include <iostream>

using namespace std;


//declaring a class Rectangle

class Rectangle {

    int width, height; //attributes width and height are not under any access specifier, so they are private members

  public:

    void set_values (int,int);

    int area() {return width*height;}  //inline definition of member function area()

};


//defining member functions of class Rectangle

void Rectangle::set_values (int x, int y) {

  width = x;

  height = y;

}


int main () {

  Rectangle rect; //declaring a Rectangle object, rect

  rect.set_values (3,4); //use member function of rect

  cout << "area: " << rect.area();

  return 0;

}

In this example, a class called `Rectangle` is defined using the `class` keyword. Inside the class, we have two data members: `width` and `height`, which are both integers. We also have two member functions: `set_values()` and `area()`. The `set_values()` function takes two integer parameters and sets the values of the `width` and `height` data members. The `area()` function calculates and returns the area of the rectangle by multiplying the values of the `width` and `height` data members.

Note

In the `main()` function, an object of the `Rectangle` class called `rect` is created. We then call the `set_values()` function on the `rect` object to set its width and height to 3 and 4, respectively. Finally, we call the `area` function on the `rect` object to calculate and print its area.

c. C++ Object

In C++, an object is an instance of a class. For example, in real life, a car as a class has attributes, such as weight and color, and methods, such as drive and brake. An object as an instance of a class in C++ has several properties, including size (which can be determined with `sizeof`), storage duration (automatic, static, dynamic, thread-local), lifetime (bounded by storage duration or temporary), and type. C++ objects are created, destroyed, referred to, accessed, and manipulated in C++ programs.

In C++, you can declare an object of a class by specifying the class name followed by the object name if the class has no parameterized constructor:

ClassName objectName;

For example, 

Rectangle rect; //declaring a Rectangle object, rect

If a class has a parameterized constructor, declaring an object of a class is done by specifying the class name followed by the object name with arguments in the constructor declaration. For example (please test it in the online C++ compiler (IDE)):

#include <iostream>

#include <string>


class Person {

public:

    Person(const std::string& name, int age) : name(name), age(age) {}

    void introduce() const {

        std::cout << "Hello, my name is " << name << " and I am " << age << " years old." << std::endl;

    }

private:

    std::string name;

    int age;

};


int main() {

    Person alice("Alice", 25); //declaring a Person object, alice

    alice.introduce();

}

In this example, we define a `Person` class with a constructor that takes two arguments: a `name` and an `age`. The constructor initializes the `name` and `age` data members of the `Person` object. In the `main()` function, we declare an object of the `Person` class named `alice`, and pass `"Alice"` and `25` as arguments to the constructor. This creates a `Person` object with the name `"Alice"` and the age `25`. We can then call the `introduce` method on the `alice` object to make it introduce itself.

d. Relationships

In C++, there are several types of relationships between classes. Some of the most common relationships include:

Is-a(n): This relationship is also known as inheritance, where one class is a subtype of another class. For example, a square "is-a" shape.

Has-a(n): This relationship is also known as composition or aggregation, where one class contains an instance of another class. For example, a car "has-an" engine.

Uses-a(n): This relationship is where one class uses another class. For example, a programmer "uses-a" keyboard.

Depends-on: This relationship is where one class depends on another class. For example, a flower "depends-on" a bee for pollination.

Member-of: This relationship is where one class is a member of another class. For example, a receptionist is a "member-of" the staff.

These relationships help define the structure and behavior of objects in C++ programs and can be useful in improving code reusability and extensibility.

Here's an example of a composition relationship in C++:

class Engine {

public:

    void start() { /*...*/ }

};


class Car {

private:

    Engine engine;

public:

    void start() { engine.start(); }

};

In this example, the `Car` class has a `Engine` object as a member variable. This means that a `Car` "has-a" `Engine`. The `Car` class uses the `Engine` object to implement its own `start` method. This is an example of a composition relationship, where one class contains an instance of another class.

Here's an example of a uses-a relationship in C++:

class Keyboard {

public:

    void type() { /*...*/ }

};


class Programmer {

public:

    void writeCode(Keyboard& keyboard) { keyboard.type(); }

};

In this example, the `Programmer` class has a method `writeCode` that takes a `Keyboard` object as an argument. This means that a `Programmer` "uses-a" `Keyboard`. The `Programmer` class uses the `Keyboard` object to implement its own `writeCode` method. This is an example of a uses-a relationship, where one class uses another class. 

Here's an example of a depends-on relationship in C++:

class Bee {

public:

    void pollinate(Flower& flower) { /*...*/ }

};


class Flower {

public:

    void bloom() { /*...*/ }

};

In this example, the `Bee` class has a method `pollinate` that takes a `Flower` object as an argument, which means that a `Bee` "depends-on" a `Flower`. The `Bee` class uses the `Flower` object to implement its own `pollinate` method. This is an example of a depends-on relationship, where one class depends on another class.

In C++, the member-of relationship is also known as the has-a relationship or composition. This relationship is used when one class contains an instance of another class as a member. Here's an example of a `Car` class that has a `Wheel` class as its member:

class Wheel {

public:

    int size;

    Wheel(int size) : size(size) {}

};


class Car {

public:

    Wheel wheel;

    Car(int wheelSize) : wheel(wheelSize) {}

};


In this example, the `Car` class has a `Wheel` object as its member, which means that every `Car` object has a `Wheel` object. The `Car` constructor takes an integer argument for the size of the `Wheel` and passes it to the `Wheel` constructor to create a `Wheel` object of the specified size.

e. Encapsulation

In C++, encapsulation is a fundamental concept of object-oriented programming that involves the bundling of data members and functions that operate on them inside a single class. This helps to keep related data and functions together, making the code cleaner and easier to read.

Encapsulation also provides data protection and information hiding. By keeping the data members of a class private, access to and modification of these data members is restricted to the class's public methods, ensuring controlled and secure data manipulation. This also hides the internal implementation details of a class from external code, providing abstraction and simplifying the usage of the class while allowing the internal implementation to be modified without impacting external code.

Generally, to access private attributes of a class, we design public get() (called getter) and set() (called setter) methods.  For example (please test in the the online C++ compiler (IDE),

#include <iostream>

using namespace std;

class Employee {

  private:

    // Private attribute

    int salary;


  public:

    // Setter

    void setSalary(int s) {

    salary = s;

    }

    // Getter

    int getSalary() {

      return salary;

    }

};


int main() {

  Employee myObj;

  myObj.setSalary(50000);

  cout << myObj.getSalary();

  return 0;

}

In this example, The salary attribute is private, which have restricted access. The public setSalary() method takes a parameter (s) and assigns it to the salary attribute (salary = s). The public getSalary() method returns the value of the private salary attribute. Inside main(), we create an object of the Employee class. Now we can use the setSalary() method to set the value of the private attribute to 50000. Then we call the getSalary() method on the object to return the value.

f. Inheritance

In C++, inheritance is a mechanism that allows a new class to be created from an existing class. We call the new class as the derived class or child class, and the existing class as the base class or parent class. The derived class inherits all the attributes and methods of the base class, which means that it can reuse the code from the base class.

Here's an example of inheritance in C++ (please test it in the the online C++ compiler (IDE)):

#include <iostream>

using namespace std;


// Base class

class Vehicle {

public:

    string brand = "Ford";

    void honk() {

        cout << "Tuut, tuut! \\n";

    }

};


// Derived class

class Car: public Vehicle {

public:

    string model = "Mustang";

};


int main() {

    Car myCar;

    myCar.honk();

    cout << myCar.brand + " " + myCar.model;

    return 0;

}

In this example, the `Car` class is derived from the `Vehicle` class using the (:) symbol. The `public` keyword specifies that all public members of the `Vehicle` class should also be public members of the `Car` class. As a result, the `Car` object `myCar` can access both the `brand` attribute and the `honk()` method from the `Vehicle` class, as well as its own `model` attribute.

Note: as we mentioned earlier, class Car can also access protected members of class Vehicle if Vehicle has protected members because it is inherited from class Vehicle. But class Car cannot access any private member of class Vehicle.

Inheritance is useful for code reusability and can help to reduce code duplication.

In C++, multilevel inheritance refers to a type of inheritance where a class is derived from another derived class. This means that a class can inherit from a base class, and then another class can inherit from that derived class, creating a chain of inheritance.

Here's an example of multilevel inheritance in C++:

class A {

public:

    void display() {

        cout << "Base class content.\\n";

    }

};


class B : public A {};


class C : public B {};


int main() {

    C obj;

    obj.display();

    return 0;

}

In this example, `class B` is derived from the base `class A`, and `class C` is derived from the derived `class B`. The `obj` object of `class C` is defined in the `main()` function. When the `display()` function is called, `display()` in `class A` is executed because there is no `display()` function in `class C` and `class B`. The compiler first looks for the `display()` function in `class C`. Since the function doesn't exist there, it looks for the function in `class B` (as `C` is derived from `B`). The function also doesn't exist in `class B`, so the compiler looks for it in `class A` (as `B` is derived from `A`).

In C++, multiple inheritance is a feature that allows a class to inherit from more than one base class³. This means that a derived class can have multiple base classes and inherit the attributes and methods from all of them³.

Here's an example of multiple inheritance in C++:

#include <iostream>

using namespace std;

class Base1 {

public:

    void display() {

        cout << "Base1\\n";

    }

};


class Base2 {

public:

    void display() {

        cout << "Base2\\n";

    }

};

class Derived : public Base1, public Base2 {};

int main() {

    Derived obj;

    obj.Base1::display();

    obj.Base2::display();

    return 0;

}

In this example, the `Derived` class is derived from both `Base1` and `Base2` using the `:` symbol and a comma-separated list of base classes. The `obj` object of the `Derived` class is defined in the `main()` function. When the `display()` function is called, it must be specified which base class's `display()` function should be called, as both `Base1` and `Base2` have a `display()` function³. This is done by using the scope resolution operator `::` and specifying the base class name before the function name.

Multiple inheritance can be useful in some situations, but it can also introduce complexity and ambiguity.

g. Polymorphism

Polymorphism means multiple forms - it is a fundamental concept in object-oriented programming that allows objects of different classes to be treated as objects of a common superclass. 

For example, think of a base class called Animal that has a method called animalSound(). Derived classes of Animals could be Pigs, Cats, Dogs, Birds - And they also have their own implementation of an animal sound (the pig oinks, and the cat meows, etc.) (C# Polymorphism (w3schools.com) ): 

#include <iostream>

using namespace std;


// Base class

class Animal {

  public:

    void animalSound() {

    cout << "The animal makes a sound \n";

}

};


// Derived class

class Pig : public Animal {

  public:

    void animalSound() {

    cout << "The pig says: wee wee \n";

    }

};


// Derived class

class Dog : public Animal {

  public:

    void animalSound() {

    cout << "The dog says: bow wow \n";

    }

};


int main() {

  Animal myAnimal;

  Pig myPig;

  Dog myDog;


  myAnimal.animalSound();

  myPig.animalSound();

  myDog.animalSound();

  return 0;

}

Redefining a function ( like animalSound() in this example) in derived classes (like Pig and Dog in this example) is called function overriding. Function overriding in C++ is a feature of inheritance that allows a derived class to provide a new implementation for a function that is already defined in its base class. The function in the derived class must have the same signature as the function in the base class, which means it must have the same name, return type, and parameters. The redefined function will replace the original function in the derived class. 

Function overriding allows for runtime polymorphism, where the behavior of a function can change depending on the type of object that it is called on.

In C++, runtime polymorphism is generally achieved through the use of virtual functions. A virtual function is a member function that has no definition in the base class but can be redefined (overridden) by derived classes. When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class's version of the function. Virtual functions are mainly used to achieve runtime polymorphism.

Virtual functions are declared with the `virtual` keyword in the base class, and the resolving of the function call is done at runtime. This means that the actual function that is called is determined by the type of the object pointed to by the pointer or reference, rather than by the type of the pointer or reference itself.

Here's an example of runtime polymorphism with a virtual function in C++:

#include <iostream>

using namespace std;


class Shape {  //base class

public:

    virtual void draw() = 0; // pure virtual function

};


class Circle : public Shape { //derived class

public:

    void draw() { //redefine the virtual function from the base class

        cout << "Drawing Circle" << endl;

    }

};


class Rectangle : public Shape { //derived class

public:

    void draw() { //redefine the virtual function from the base class

        cout << "Drawing Rectangle" << endl;

    }

};


int main() {

    Shape *s1 = new Circle();

    Shape *s2 = new Rectangle();

    s1->draw();

    s2->draw();

    delete s1;

    delete s2;

    return 0;

}

In this example, the `Shape` class has a pure virtual function `draw()` that is overridden by the `Circle` and `Rectangle` classes, which are derived from the `Shape` class. In the `main()` function, two pointers to `Shape` objects are created and assigned to new `Circle` and `Rectangle` objects. When the `draw()` function is called on these pointers, the appropriate version of the function is called based on the actual type of the object pointed to by the pointer.

Polymorphism allows for greater flexibility and code reusability, as it enables the creation of generic functions and data structures that can work with objects of different classes.

h. Function overloading


Function overloading is a feature of C++ that allows you to create multiple functions with the same name but different parameters. Which function to be called is determined by the compiler based on the number, types, and order of the arguments passed. Function overloading is useful when you want to perform similar operations on different data types.


An example of function overloading in C++ is here:


#include <iostream>

using namespace std;


int add(int x, int y) {

   return x + y;

}


double add(double x, double y) {

   return x + y;

}


int main() {

   cout << add(5, 10) << endl;

   cout << add(5.0, 10.0) << endl;

   return 0;

}



In this example, we have two functions named `add()`. The first function takes two integers as arguments and returns their sum. The second function takes two doubles as arguments and returns their sum. When we call the `add()` function with integers, the first version of the function is called. When we call it with doubles, the second version is called.

j. Friend function

A friend function in C++ is a function that is not a member of a class but has access to the class's private and protected members. A friend function can be declared inside or outside the class definition using the keyword `friend`. 

Here's an example of a friend function in C++:

#include <iostream>


using namespace std;


class MyClass {

   private:

      int x;

   public:

      MyClass() : x(0) {}

      friend void setX(MyClass& obj); //declaring a friend function

};


void setX(MyClass& obj) {

   obj.x = 25;

}


int main() {

   MyClass obj;

   setX(obj);

   cout << obj.x << endl;

   return 0;

}

In this example, we have a class named `MyClass` with a private member variable `x`. We also have a friend function named `setX()` that takes an object of type `MyClass` as an argument and sets its `x` member variable to 25. The `setX()` function can access the private member variable of the `MyClass` object because it is declared as a friend of the class.

16. Templates

Templates are a feature of C++ that allows you to write generic code that can work with different data types. A template is a blueprint or formula for creating a generic class or function. 

a. Function templates

A function template defines a family of functions. The syntax for defining a function template is

template < parameter-list

function-declaration

This template definition must be in the same module where it can be used. C++ 20 introduced keyword export to define function template such as 

export template < parameter-list

function-declaration

The export keyword is used for templates to specify that the template definition should be exported from the module in which it is defined, so that the template definition can be used by other modules that import the module in which the template is defined. 


The general form of a function template definition syntax is

template <typename type

return_type functionName(parameter list)

{

    // body of function

}

Here's an example of a function template in C++:

#include <iostream>

using namespace std;


template <typename T>

T add(T x, T y) {

   return x + y;

}


int main() {

   cout << add(5, 10) << endl;

   cout << add(5.0, 10.5) << endl;

   return 0;

}

The output should be 

15

15.5

In this example, we have a function template named `add()` that takes two arguments of the same type and returns their sum. The type of the arguments is specified using the `typename` keyword followed by the name of the type parameter (`T` in this case). When we call the `add()` function with integers, the first version of the function is called. When we call it with doubles, the second version is called.

b. Class templates

A class template defines a family of classes. The syntax for defining a class template is

template < parameter-list

class-declaration

or 

export template < parameter-list

class-declaration

Here's an example of a class template in C++:

#include <iostream>

using namespace std;


template <typename T>

class MyClass {

   private:

      T x;

   public:

      MyClass(T val) : x(val) {}

      T getX() { return x; }

};


int main() {

   MyClass<int> obj1(5);

   MyClass<double> obj2(5.5);

   cout << obj1.getX() << endl;

   cout << obj2.getX() << endl;

   return 0;

}


The output should be 

5

5.5

In this example, we have a class template named `MyClass` that takes a type parameter `T`. The class has a private member variable `x` of type `T`, and a public member function `getX()` that returns the value of `x`. We create two instances of the `MyClass` template, one with an integer type parameter and one with a double type parameter.

c. C++ Standard Template Library

The C++ Standard Library provides a wide range of facilities that are usable in standard C++ (C++ Standard Library - cppreference.com ). The Standard Template Library (STL) is a software library originally designed by Alexander Stepanov for the C++ programming language that influenced many parts of the C++ Standard Library. It provides four components called algorithms, containers, functions, and iterators(Standard Template Library - Wikipedia

The STL implements data structures and algorithms using general-purpose classes and functions that have been tested rigorously.  Here are some examples of C++ STL:

To explore more details of STL, we need study data structures and algorithms first. So that we will temporarily stop here. 

17. Exception handling

Exception handling is a mechanism in C++ that allows you to handle errors and other exceptional events that occur during program execution. 

C++ handles exceptions using the try, catch, and throw keywords. throw is used to throw an exception and is enclosed in the try block. If an exception is thrown, the program jumps to the nearest catch block that matches the type of the exception. The throw statement is used to throw an exception with a specific message or error code. 

The syntax of exception handling in C++ is as follows:

try {

   // code to throw an exception

} catch (exception_type1 e1) {

   // code to handle exception of type exception_type1

} catch (exception_type2 e2) {

   // code to handle exception of type exception_type2

} catch (...) {

   // code to handle other type of exception

}


In this syntax, the try block has code that may throw an exception. If an exception is thrown, the program jumps to the nearest catch block that matches the type of the exception. The catch blocks contain code to handle the exceptions.

Here's an example of exception handling in C++ (please test it in the online C++ compiler (IDE):

#include <iostream>

using namespace std;


int main() {

   try {

      int x = 10;

      int y = 0;

      if (y == 0) {

         throw "Division by zero!";

      }

      int z = x / y;

      cout << z << endl;

   } catch (const char* msg) {

      cerr << msg << endl;

   }

   return 0;

}

The execution output shall be 

Division by zero!

In this example, we have a `try` block that contains code that may throw an exception. We attempt to divide the integer `x` by the integer `y`, but since `y` is zero, this will result in a division by zero error. We use the `throw` statement to throw an exception with the message "Division by zero!". We then have a `catch` block that catches the exception and prints the error message to the standard error stream.

If we remove the throw statement in the above example, the program becomes

#include <iostream>

using namespace std;


int main() {

   try {

      int x = 10;

      int y = 0;

      int z = x / y;

      cout << z << endl;

   } catch (const char* msg) {

      cerr << msg << endl;

   }

   return 0;

}

The execution output shall be 

Floating point exception

In this program, we do not manually throw a message for an exception. Since the division by zero code is in the try block, the exception shall be caught by the system, and the catch block shall process the exception. In this example, it simply output the exception message to cerr.  

References

(Referred in August 2023)