C++ PROGRAMMING CRASH COURSE

User avatar
Eli
Senior Expert Member
Reactions: 183
Posts: 5334
Joined: 9 years ago
Location: Tanzania
Has thanked: 75 times
Been thanked: 88 times
Contact:

#1

This rapid crash course in C++ programming is far from being complete -- materials presented here are subject to change, and will be continuously updated. More contents will periodically be added to cover all fundamental concepts in C++ programming.

Run codes as you go...

Use Mozilla Firefox for better experience




Float and Double

In programming, particularly, C++, float and double are both used for the representation of fractional/decimal numbers. In other words, the difference between float and double arises from the fact with how much precision (the degree/quality of being exact and accurate) they can store the numbers. For example, one may decide to store a mathematical constant \(\pi\) as 3.14 or 3.14159. A variable able to store \(\pi\) as 3.14159 provides more precision than the one able to hold \(\pi\) as 3.14. Float can accurately store about 7 - 8 digits in the fractional part while double can accurately store about 15 - 16 digits in the fractional part. These fractions/decimals can amount to a huge difference in large calculations and significantly affect results.

Single precision floating point and Double precision floating point

Precision in computer science is the use of a higher level of detail to express the same number. Instead of using decimal points to represent the number, we use bits, or binary digits to express such a number. If we think of a number such as $\pi$ expressed in traditional scientific notation \(3.14 \times 10^{0}\), computers store such a number in binary as a floating-point, a series of ones and zeroes that represent a number and its corresponding exponent. According to the IEEE 754 standard, floating-point numbers are commonly represented in two ways, single and double precision formats. In single-precision format, each number takes up to 32 bits, also called binary32 (this means a number occupies 32 bits in computer memory), and double-precision format uses up to 64 bits (binary64 -- it occupies 64 bits in computer memory). The range of numbers in single-precision is \(2^{(-126)}\) to \(2^{(+127)}\), and the range of numbers in double precision is \(2^{(-1022)}\) to \(2^{(+1023)}\).

In a single-precision, that is a 32-bit format, one bit (signed bit) is used to tell whether the number is positive or negative. Eight bits are reserved for the exponent, a power to base 2 (because it’s binary). The remaining 23 bits are used to represent the fractional digits/bits that make up the number, called the mantissa. Double precision instead uses 11 bits for the exponent and 52 bits for the mantissa. Double floating-point precision expands the range and size of numbers it can represent, hence representing numbers in higher details than single precision. See also (here) for half-precision, multi-precision, and mixed precision.

\[
\begin{array}{|c|c|c|c|c|c|}
\hline
\text{Precision} &\text{Base}& \text{Sign} & \text{Exponent} & \text{Mantissa} & \text{Significand}\\
\hline
\text{Single Precision}& 2 & 1 & 8 & 23 & 23 + 1 \\
\hline
\text{Double Precision}& 2 & 1 & 11 & 52 & 52 + 1 \\
\hline
\end{array}
\]
Note that, the higher the precision level a computer uses, the more computational resources, the more RAM, data transfer, memory storage, and so on it requires. High precision is thus computationally more costly and consumes more power as well.

Summary

Single precision

Image

Ref: Image by geeksforgeeks

The IEEE single-precision floating-point standard representation requires a 32-bit word, which may be represented as numbered from 0 to 31, left to right:
  • The first bit is the sign bit, S,
  • the next eight bits are the exponent bits, 'E', and
  • the final 23 bits are the mantissa 'M' (also called fraction or coefficient):
  1. S EEEEEEEE  MMMMMMMMMMMMMMMMMMMMMMM
  2. 0 1      8  9                    31




Double precision

Image

Ref: Image by geeksforgeeks

The IEEE double-precision floating-point standard representation requires a 64-bit word, which may be represented as numbered from 0 to 63, left to right:
  • The first bit is the sign bit, S,
  • the next eleven bits are the exponent bits, 'E', and
  • the final 52 bits are the mantissa 'M':
  1. S EEEEEEEEEEE  MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  2. 0 1        11  12                                                63


Usually, the sign bits are the last, being the 31st bit and 63rd bit, in single and double precision, respectively. So the correct representation of a single-precision using a word of 32 bit, and double-precision using a word of 64 bit, would respectively look as follows:
  • 1 bit for the sign, S,
  • 8 bits for the exponent, 'E',
  • 24 bits for mantissa (note that only 23 are represented below):
  1. S  EEEEEEEE   MMMMMMMMMMMMMMMMMMMMMMM
  2. 31 30    23   22                    0


and,

  • 1 bit for the sign, S,
  • 11 bits for the exponent, 'E',
  • 53 bits for mantissa (note that only 52 are represented below):
  1. S  EEEEEEEEEEE   MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  2. 63 62       52   51                                                 0


Usually, mantissa has, in both cases, an extra bit of information (one bit) compared to its representation above. A mantissa is a number represented without all its non-significative 0 (hence the term significand). For example,
  • \(0.00135\) which becomes \(1.35 \times 10^{−3}\) in scientific notation, has three significant figures: 1, 3, and 5. Leading zeros -- zeros before non-zero numbers are not significant.
  • \(0.000122300 = 1.22300 \times 10^{-4}\) in scientific notation and has six significant figures. See more here.
This means that the mantissa will always be of the form \(0.\alpha_1\alpha_2 ...\alpha_{t} \times b^{E}\) where \(b\) is the base of representation, in this case \(2\), and \(E\) is the exponent. But since the fraction/mantissa is a binary number, \(\alpha_1\) will always be equal to \(1\), thus the fraction can be rewritten as \(1.\alpha_2\alpha_3...\alpha_{t+1} \times 2^{E}\) (scientific notation) and the first bit of mantissa/fraction is implied (suggested but not explicitly shown), making room for an extra bit (\(\alpha_{t+1}\)). As an example, \(\pi = 3.14 \times 10^{0}\) can be represented as \(1. 1100100011110101 \dots \times 2^1\) in standard scientific notation after conversion into binary form.

Single and double precision do not originate from the fact that the double of \(32\) is \(64\), but rather the precision indicates the number of decimal digits that are correct, i.e. without any kind of representation error or approximation. In other words, precision indicates the number of decimal digits one can safely use. Therefore, the number of decimal digits which can be safely used, can respectively be estimated for single and double precision as follows:
  • Single precision: \({\text log}_{10}(2^{24})\), which is about \(7\sim 8\) decimal digits.
  • Double precision: \({\text log}_{10}(2^{53})\), which is about \(15\sim 16\) decimal digits.
Ref: StackOverflow.


Scientific Notation

Let us convert \(3.14\) to scientific notation under base 2.

Step 1: Divide the whole part, i.e., \(3\) and the resulting output throughout by 2 and record the remainder in each step. Stop when the division output is \(0\).

\[
\begin{array}{|c|c|c|}
\hline
\text{Divisor} &\text{Dividend}& \text{Remainder}\\
\hline
2 & 3 & \\
\hline
2 & 1 & 1 \\
2 & 0& 1\\
\hline
\end{array}
\]

Here, the binary number for \( 3\) is the sequence of ones in the "Remainder" column above, written from down to the top. Thus, \( 3 \equiv 11 \) in binary form.

Step 2: Convert the fractional part, \(0.14\) into binary form by multiplying it by \(2\) and recording the value of the output before the decimal point. Repeatedly multiply the resulting decimals/fractions by \(2\) and record the values before the decimal point:

\[
\begin{array}{|c|c|c|}
\hline
\text{Multiply by 2} &\text{Result}& \text{Value before decimal point}\\
\hline
0.14 \times 2 & 0.28 & 0\\
\hline
0.28 \times 2 & 0.56 & 0\\
\hline
0.56 \times 2 & 1.12& 1\\
\hline
0.12 \times 2 & 0.24 & 0\\
\hline
0.24 \times 2 & 0.48 & 0\\
\hline
0.48 \times 2 & 0.96 & 0\\
\hline
0.96 \times 2 & 1.92 & 1\\
\hline
0.92 \times 2 & 1.84 & 1\\
\hline
0.84 \times 2 & 1.68 & 1\\
\hline
0.68 \times 2 & 1.36 & 1\\
\hline
0.36 \times 2 & 0.72 & 0\\
\hline
0.72 \times 2 & 1.44 & 1\\
\hline
0.44 \times 2 & 0.88 & 0\\
\hline
0.88 \times 2 & 1.76 & 1\\
\hline
\dots & \dots & \dots \\
\hline
\end{array}
\]

From the table, \(0.14 \equiv 0.00100011110101 \) in binary form. Thus, in binary form, \(3.14 \equiv 11.00100011110101\).

In scientific notation (base 2), \(3.14 \equiv 11.00100011110101 = 1.100100011110101 \dots \times 2^{1} \).



Single Precision Floating Point Representation


Let us convert the number \(263.3\) into a single-precision floating-point representation.

Step 1: Convert the whole part, \(263\) into a binary system: Divide \(263\) and the resulting output throughout by 2 and record the remainder in each step. Stop when the division output is \(0\).

\[
\begin{array}{|c|c|c|}
\hline
\text{Divisor} &\text{Dividend}& \text{Remainder}\\
\hline
2 & 263 & \\
\hline
2 & 131 & 1 \\
\hline
2 & 65 & 1\\
\hline
2 & 32 & 1\\
\hline
2 & 16 & 0\\
\hline
2 & 8 & 0\\
\hline
2 & 4 & 0\\
\hline
2 & 2 & 0\\
\hline
2 & 1 & 0\\
\hline
& 0 & 1\\
\hline
\end{array}
\]

The binary number is a sequence of ones and zeroes in the "Remainder" column above, written from down to the top. Thus \(263\) in binary form is \(100000111\).

To convert \(0.3\) into binary form, we multiply it by \(2\) and record the value of the output before the decimal point (this is either \(0\) or \(1\)). We repeatedly multiply the resulting decimals/fractions by \(2\) and record the values before the decimal point:

\[
\begin{array}{|c|c|c|}
\hline
\text{Multiply by 2} &\text{Result}& \text{Value before decimal point}\\
\hline
0.3 \times 2 & 0.6 & 0\\
\hline
0.6 \times 2 & 1.2 & 1\\
\hline
\hline
0.2 \times 2 & 0.4 & 0\\
\hline
0.4 \times 2 & 0.8 & 0\\
\hline
0.8 \times 2 & 1.6 & 1\\
\hline
0.6 \times 2 & 1.2 & 1\\
\hline
\hline
\dots & \dots & \dots \\
\hline
\end{array}
\]

From the table above, we can write \(0.3\) in binary form as \(.01001100110011\dots\).

Therefore, \(263.3\) in binary form is \(100000111.01001100110011\dots\).

In scientific notation (we shift the decimal point \(8\) positions to the left and multiply the result by \(2\) raised to some power):

\[ 1.00000111010011001100110\dots \times 2^{8} \].

Recall the single-precision floating-point (binary32) format

  1. S EEEEEEEE  MMMMMMMMMMMMMMMMMMMMMMM
  2. 0 1      8  9                    31



and consider the following:
  • If the number being considered is positive, the sign bit, \(S = 0\).
  • If the number being considered is negative, the sign bit, \(S = 1\).
  • We need to take into account the exponent bias. For a single precision floating point (IEEE 754 format), the bias is given by \(2^{(\text{Number of exponent bits} - 1)} - 1 = 2^{(8-1)} - 1 = 2^7 - 1 = 127\).

    "We have 8 bits to represent the exponent. We can represent \(2^8 = 256\) numbers with \(8\) bits. The bias is considered to be half of it minus 1 so that we can represent both positive and negative exponents." See comments here.
    \(\\ \)
  • We need to add the exponent in the standard notation (the power of 2 -- which can be positive or negative) to the bias obtained above. Adding bias to the exponent, we have \(127 + 8 = 135\).


Now, let's convert the resulting \(135 \) into binary format:

\[
\begin{array}{|c|c|c|}
\hline
\text{Divisor} &\text{Dividend}& \text{Remainder}\\
\hline
2 & 135 & \\
\hline
2 & 67 & 1\\
\hline
2 & 33 & 1\\
\hline
2 & 16 & 1\\
\hline
2 & 8 & 0\\
\hline
2 & 4 & 0\\
\hline
2 & 2 & 0\\
\hline
2& 1 & 0\\
\hline
& 0 & 1\\
\hline
\end{array}
\]

Therefore, \(135\) in binary form is \(10000111\).

Let's now write our number, \(263.3\) in binary32 following the convention,

\[
\begin{array}{|c|c|c|}
\hline
\text{S} &\text{E...E}& \text{M...M}\\
\hline
1 \ \text{Sign bit} & 8 \ \text{Exponent bits} & 23 \ \text{Fraction/Mantissa bits}\\
\hline
0 & 10000111& 00000111010011001100110 \\
\hline
\end{array}
\]

Thus, \(263.3\) in IEEE754 single-precision floating-point representation is \(01000011100000111010011001100110\).

Here, the fractional bits (mantissa) are the bits that follow the decimal point in scientific notation, \( 1.00000111010011001100110\dots \times 2^{8} \), that is \[ 00000111010011001100110\].

Ref:




Convert IEEE 754 Single-Precision (32-bit) Floating-Point Representation to Equivalent Decimal Number

We can reverse the binary number (binary32) into its equivalent decimal number. Let us find the decimal equivalent for the following binary32:

  1. 0 10000101 11110110000000000000000


Sign bit

From the given binary32, we see that the signed bit = 0, so the decimal equivalent number is positive. This is because, our decimal equivalent is calculated from the binary representation:
\begin{align}
(-1)^{S}\times(1+M)\times 2^{E} = (-1)^{S}\times(1.M)\times 2^{E},
\end{align}
where \(S\) is the signed bit, and \(M\) is the mantissa.


Exponent bits:

In scientific notation the binary32 takes the form \(1.M \times 2^{E} \), where \(M\) is the mantissa and \(E\) is the exponent.

We convert the exponent bits from binary to decimal as follows:

\begin{align}\nonumber
\begin{cases}
(10000101)_{2} & = & 1 \times 2^0 + 0 \times 2^1 + 1 \times 2^2 + 0 \times 2^3 + 0 \times 2^4 + 0 \times 2^5 + 0 \times 2^6 + 1 \times 2^7\\
& & \text{(1, 0, 1, ... are multiplied from right to left)}\\
& = & 1 + 0 + 4 + 0 + 0 + 0 + 0 + 128 \\
&=& 133.
\end{cases}
\end{align}

The exponential bias for binary32 = \(2^{8 -1} - 1 = 127 \), and so any exponent bits that represent a number less than \(127\) would result in a negative exponent \(E\) (refer the scientific notation section). Since \(133>127\), we have \(E = 133 - 127 = 6 \) (here, exponent bit was added to the bias).

Therefore, in scientific notation our number now takes the form
\begin{align}\label{eq2}
\begin{split}
1.M\times 2^{6} & = 1.11110110000000000000000 \times 2^{6}\\
&= 1111101.10000000000000000.
\end{split}
\end{align}


Convert the whole part into decimal number:

We convert the whole part (binary) from Equation (\ref{eq2}) into decimal number:

\begin{align}\nonumber
\begin{cases}
(1111101)_{2} & = & 1 \times 2^0 + 0 \times 2^1 + 1 \times 2^2 + 1 \times 2^3 + 01\times 2^4 + 1 \times 2^5 + 1 \times 2^6 \\
& & \text{(1, 0, 1, ... are multiplied from right to left)}\\
& = & 1 + 0 + 4 + 8 + 16 + 32 + 64\\
&=& 125.
\end{cases}
\end{align}

Convert the fractional part into decimal

We convert the fractional part (binary) from Equation (\ref{eq2}) into decimal number:

\begin{align}\nonumber
\begin{cases}
(0.100\dots)_{2} &=& 1 \times 2^{-1} + 0 \times 2^{-2} + \dots \\
&=& 0.5 + 0 + 0 + \dots\\
&=& 0.5.\\
\end{cases}
\end{align}

Finally, the decimal equivalent number is given by the sum of the whole part and the fractional part, thus our decimal number is \(125.5\).


After seeing the example above, we can now easily reverse from binary32,

  1. 0  10000111  00000111010011001100110


to \(263.3\) as follows:

Calculate the exponent from the exponent bits (from base 2 to base 10):

\begin{align}
\begin{split}
(10000111)_{2} & = 1\times 2^{0} + 1\times 2^{1} + 1\times 2^{2} + 0 \times 2^{3} + 0 \times 2^{4} + 0 \times 2^{5} + 0 \times 2^{6} + 1 \times 2^{7}\\
& = 1 + 2 + 4 + 0 + \dots + 0 + 128\\
& = 135\\
\implies & E = 135 - 127 = 8.
\end{split}
\end{align}

From scientific notation in binary form, our number takes the form

\begin{align}
\begin{split}
1.M \times 2^{8} & = 100000111.010011001100110\\
& = 2^{0} + 2^{1} +2^{2}+0+0+0+0+0+2^{8} \ \text{(whole part)}\\
& + 0\times 2^{-1} + 1\times 2^{-2} + 0\times 2^{-3} + 0\times 2^{-4} + 1\times 2^{-5} \\
& + 1\times 2^{-6} + 0\times 2^{-7} + 0\times 2^{-8} + 1\times 2^{-9} + 1\times 2^{-10} \\
& + 0\times 2^{-11} + 0\times 2^{-12} + 1\times 2^{-13} + 1\times 2^{-14} + 0 \ \text{(fractional part)} \\
& = (1 + 2 + 4 + 256) \\
& + \frac{1}{4} + \frac{1}{32} + \frac{1}{64} + \frac{1}{512} + \frac{1}{1024} + \frac{1}{8192} + \frac{1}{16384}\\
\\
& = 263 + 0.29998779296875\\
& \approx 263.3.
\end{split}
\end{align}

Input and Output

Consider the program below:

  1. #include<iostream>
  2.  
  3. int main ()
  4. {
  5.  
  6. char i1 = 25;
  7.  
  8. std::cout<<"The answers to the Ultimate Question of Life, \n"
  9. <<"the Universe, and Everything are:"
  10. <<std::endl<< 8*9 <<std::endl;
  11. std::cout<< i1*2 <<std::endl;
  12. std::cout<< "and"<<std::endl;
  13. std::cout<< 'a' + 12 <<std::endl;
  14.  
  15. return 0;
  16. }


Input and output are not part of the core language but are provided by the library. They must be included explicitly; otherwise, we cannot read or write.

The standard I/O (input - output) has a stream model and is therefore named <iostream>. To enable its functionality, we include <iostream> in the first line

Every C ++ program starts by calling the function main. It does return an integer value where 0 represents a successful termination.

Braces {} denote a block/group of code (also called a compound statement).

std::cout and std::endl are defined in <iostream> . The former is an output stream that prints text on the screen. std::endl terminates a line. We can also go to a new line with the special character \n .

The operator << can be used to pass objects to an output stream such as std::cout for performing an output operation.

std:: denotes that the type or function is used from the standard Namespace. Namespaces help us to organize our names and to deal with naming conflicts.

String constants (more precisely literals) are enclosed in double quotes.

The expression 8 * 9 is evaluated and passed as an integer to std::cout. In C ++, every expression has a type. Sometimes, we as programmers have to declare the type explicitly and other times the compiler can deduce it for us. 6 and 7 are literal constants of type int and accordingly their product is int as well.


Variables

C ++ is a strongly typed language (in contrast to many scripting languages). This means that every variable has a type and this type never changes. A variable is declared by a statement beginning with a type followed by a variable name with optional initialization, for example:

  1. int i1 = 2;
  2. int i2 = 3, i3 = 5
  3.  
  4. char c1 = 'a', c2 = 25;
  5. float pi = 3.14159;
  6. bool bl = i1<pi, //-> true
  7. sad = true;


Basic types (Variables) (also called Intrinsic Types)

All variables use data-type during declaration to restrict the type of data to be stored. Therefore, we can say that data types are used to tell the variables the type of data it can store. Whenever a variable is defined in C++, the compiler allocates some memory for that variable based on the data-type with which it is declared. Every data type requires a different amount of memory.


\[
\begin{array}{|c|c|}
\hline
\text{Name/Keyword} & \text{Semantics (Meaning)} \\
\hline
\text{char} & \text{8-bit signed data item. Letter and very short integer number} \\
\hline
\text{short} & \text{Rather short integer number} \\
\hline
\text{int} & \text{Regular integer number. Its size is system dependent}\\
\hline
\text{long} & \text{Long integer number} \\
\hline
\text{long long} & \text{Very long integer number}\\
\hline
\text{signed} & \text{Signed versions of all the former}\\
\hline
\text{unsigned} & \text{Unsigned versions of all the former except signed}\\
\hline
\text{float} & \text{Single-precision floating-point number. 32-bit IEEE floating point number}\\
\hline
\text{double} & \text{Double-precision floating-point number. 64-bit IEEE floating-point number} \\
\hline
\text{long double} & \text{long floating-point number} \\
\hline
\text{void} & \text{Valueless or void}\\
\hline
\text{wchar_t} & \text{Unicode character accepted only for 32-bit type libraries}\\
\hline
\end{array}\]

Note:

"Unicode is a universal character encoding standard. It defines the way individual characters are represented in text files, web pages, and other types of documents.

Unlike ASCII characters, which were designed to represent only basic English characters, Unicode was designed to support characters from all languages around the world. The standard ASCII character set only supports 128 characters, while Unicode can support roughly 1,000,000 characters. While ASCII only uses one byte to represent each character, Unicode supports up to 4 bytes for each character" See more >>>.

The first five types are integer numbers of non-decreasing length. For instance, int is at least as long as short ; i.e., it is usually but not necessarily longer. The exact length of each type is a platform (implementation)-dependent; e.g., int could be 16, 32, or 64 bits. All these types
can be qualified as signed or unsigned. signed has no effect on integer numbers (except char ) since they are signed by default.

When we declare an integer type as unsigned, we will have no negative values but twice as many positive ones (plus one when we consider zero as neither positive nor negative). A signed integer is a 32-bit datum that encodes an integer in the range from -2147483648 to 2147483647. An unsigned integer is a 32-bit datum that encodes a non-negative integer in the range from 0 to 4294967295, see Ref. Unsigned integers (sometimes called "units") are just like integers (whole numbers) but have the property that they don't have a + or - sign associated with them. Thus they are always non-negative (zero or positive). signed and unsigned can be considered adjectives for the nouns short, long, char, int, with int as the default noun when the adjective only is declared.

The non-decreasing length property also applies in the same manner to floating-point numbers. float is shorter than or equally as long as double, which in turn is shorter than or equally as long as long double. Typical sizes are 32 bits for float, 64 bits for double, and 80 bits for long double.

short, long, signed, unsigned are called datatype modifiers and are used with the built-in data types to modify the length of data that a particular data type can hold. If we ignore access modifiers, the intrinsic/basic types, reduces to what is mostly agreed to be Primitive Data Types -- fundamental, or built-in, types:

\[
\begin{array}{|c|c|}
\hline
\text{Data Type} & \text{Keyword} \\
\hline
\text{Integer} & \text{int}\\
\hline
\text{Character} & \text{char}\\
\hline
\text{Boolean} & \text{bool}\\
\hline
\text{Floating Point} & \text{float}\\
\hline
\text{Double Floating Point} & \text{double}\\
\hline
\text{Valueles or Void} & \text{void}\\
\hline
\text{Wide Character} & \text{wchar_t}\\
\hline
\end{array}\]

These data types are built-in or predefined.

The type char can be used in two ways: for letters and for short numbers, and it almost always has a length of 8 bits. Thus, we can either
represent values from -128 to 127 signed) in or from 0 to 255 (unsigned) and safely perform all numeric operations on them that are available for integers. When neither signed nor unsigned is declared, it depends on the implementation of the compiler which one is used.

Note that, the C ++ compiler considers 'a' as the character "a" (it has type char) and interprets "a" as the string containing “a” and a binary 0 as termination.

Wide character (wchar_t) data type is also a character data type but has a size greater than the normal 8-bit data type, and is generally 2 or 4 bytes long.

Boolean (bool) data types are used for storing boolean or logical values. A boolean variable can store either true or false.

void is only allowed as a return type for a function, or in a function parameter list to indicate no arguments.

We summarize using the C++ code below the modified size and range of built-in datat ypes when combined with the type modifiers:

  1. //C++ program to determine sizes of data types
  2. #include<iostream>
  3.  
  4. using namespace std;
  5.  
  6. int main()
  7. {
  8. cout<< "Size of char: " <<sizeof(char)<< " byte" << endl;
  9.  
  10. cout << "Size of signed char: " <<sizeof(signed char)<< " byte" << endl;
  11.  
  12. cout<< "Size of unsigned char: " <<sizeof(unsigned char)<< " byte" << endl;
  13.  
  14. cout<< "Size of short int: " <<sizeof(short int)<< " bytes" << endl;
  15.  
  16. cout<< "Size of unsigned short int: " <<sizeof(unsigned short int)<< " bytes" << endl;
  17.  
  18. cout<< "Size of int: " <<sizeof(int)<< " bytes" << endl;
  19. cout<< "Size of signed: " <<sizeof(signed)<< " bytes" << endl; // int is the default noun
  20. cout<< "Size of unsigned: " <<sizeof(unsigned)<< " bytes" << endl; // int is the default noun
  21.  
  22. cout<< "Size of unsigned int: " <<sizeof(unsigned int)<< " bytes" << endl;
  23.  
  24. cout<< "Size of long int: " <<sizeof(long int)<< " bytes" << endl;
  25.  
  26. cout<< "Size of signed long int: " <<sizeof(signed long int)<< " bytes" << endl;
  27.  
  28. cout<< "Size of unsigned long int: " <<sizeof(unsigned long int)<< " bytes" << endl;
  29.  
  30. cout<< "Size of long long int: " <<sizeof(long long int)<< " bytes" << endl;
  31.  
  32. cout<< "Size of unsigned long long int: " <<sizeof(unsigned long long int)<< " bytes" << endl;
  33.  
  34. cout<< "Size of float: " <<sizeof(float)<< " bytes" <<endl;
  35.  
  36. cout<< "Size of double: " << sizeof(double)
  37. << " bytes" << endl;
  38.  
  39. cout<< "Size of long double: " <<sizeof(long double)<< " bytes" << endl;
  40.  
  41. cout << "Size of wchar_t: "<< sizeof(wchar_t)<< " bytes" <<endl;
  42.  
  43. return 0;
  44. }


These values (bytes) may vary from compiler to compiler, here we present the output of the code above as determined using g++ version 7.5.0 under Ubuntu Linux 18.04 LTS:

  1. Size of char: 1 byte
  2. Size of signed char: 1 byte
  3. Size of unsigned char: 1 byte
  4. Size of short int: 2 bytes
  5. Size of unsigned short int: 2 bytes
  6. Size of int: 4 bytes
  7. Size of signed: 4 bytes
  8. Size of signed: 4 bytes
  9. Size of unsigned int: 4 bytes
  10. Size of long int: 8 bytes
  11. Size of signed long int: 8 bytes
  12. Size of unsigned long int: 8 bytes
  13. Size of long long int: 8 bytes
  14. Size of unsigned long long int: 8 bytes
  15. Size of float: 4 bytes
  16. Size of double: 8 bytes
  17. Size of long double: 16 bytes
  18. Size of wchar_t: 4 bytes


auto

C ++ 11 can automatically deduce the type of a variable, for example,

  1. auto i4 = i3 + 7;


Here, the type of i4 is automatically determined and is the same as that of i3 + 7, which is int. The type remains the same, and whatever is assigned to i4 afterward will be converted to int. auto is very useful in advanced programming.


Constants

Syntactically, constants are like special variables in C ++ with the additional attribute of constancy. Since they cannot be changed, their values must be set at the point of declaration. Constants can be used wherever variables are allowed provided they are not
modified. They can also be used as arguments of types. In the code below,

  1. #include<iostream>
  2.  
  3. int main ()
  4. {
  5.  
  6. const int ci1 = 5;
  7. const int ci3; //error: uninitialized const ‘ci3’
  8. const float pi = 3.14359;
  9. const char cc = 'a';
  10. const bool bl = ci1 > pi ;
  11.  
  12. return 0;
  13.  
  14. }


the compiler will raise an error: "uninitialized const ci3", because the second constant declaration, i.e, "const int ci3;" violates the rule, that is constant values need to be initialized during declaration.


Temporaries and Literals

Data resulting from computation or manipulation with C++ may represent many different things, from simple numbers and strings, to
images and multimedia files, to abstract numerical simulations and their solutions.

C++ knows three different categories of data:
  • Variables are names for memory locations where data is stored, e.g., int i1 = 5; referring to an integer value in memory.
  • Temporaries represent values that are not necessarily stored in memory, e.g., intermediate values in compound expressions and function return
    values. And
  • Literals are values that are explicitly mentioned in the source code, e.g., the number 5 above, or the string "Hello World!".

Every number with a dot or an exponent, for example, \(2.14 \times 10^{12} \) is considered a double. Integer literals are treated as int, long, unsigned or unsigned long depending on the number of digits. Literals of other types can also be qualified by explicitly adding a suffix to indicate a type as shown in the table below:


\[
\begin{array}{|c|c|}
\hline
\text{Data Type} & \text{Keyword} \\
\hline
2 & \text{int} \\
\hline
\text{2u} & \text{unsigned} \\
\hline
\text{2l} & \text{long} \\
\hline
\text{2ul} & \text{unsigned long}\\
\hline
\text{2.0} & \text{double}\\
\hline
\text{2.0f} & \text{float}\\
\hline
\text{2.0l} & \text{long double}\\
\hline
\end{array}\]

In most cases, it is not necessary to declare the type of literals explicitly since the implicit conversion between built-in numeric types usually sets the values at the programmer’s expectation. But, here are three major reasons why we should explicitly specify the types of
literals.
  • Availability: The standard library provides a type for complex numbers where the types for the real and imaginary parts can be parameterized by the user (see below). In this case, operations are only possible between the type itself and the underlying real
    type (arguments are not converted here). As a result, it is not possible to multiply z with an int or double but with float:

    1. #include <complex>
    2.  
    3. int main ()
    4. {
    5.  
    6. std::complex<float> z(1.3 , 2.4), z2;
    7. z2 = 2.0f*z;
    8.  
    9. // Not possible
    10. z2 = 2*z; /* note: mismatched types ‘const std::complex<_Tp>’ and ‘int’ z2 = 2*z; */
    11. z2 = 2.0*z; /* note: mismatched types ‘const std::complex<_Tp>’ and ‘double’ z2 = 2.0*z;  */
    12.  
    13. // Works
    14. z2 = 2.0f*z; //float*complex<float>
    15.  
    16. return 0;
    17.  
    18. }

    \(\\ \)
  • Ambiguity: When a function is overloaded for different argument types, an argument like 0 might be ambiguous whereas a unique match may exist for a qualified argument like 0u.
  • Accuracy: The accuracy issue comes up when we work with long double. Since the non-qualified literal is a double, we might lose digits if we do not explictly assign it to a long double variable:

    1. long double d1 = 0.3333333333333333333; // May lose digits
    2. long double d2 = 0.3333333333333333333l; // Accurate


Non-decimal numbers

Octal literals/numbers

Integer literals starting with a zero are interpreted as octal numbers, for example:

  1. #include<iostream>
  2.  
  3. int main ()
  4. {
  5.  
  6. int o1 = 042; // int o1 = 34;
  7. int o2 = 0106; // int o2 = 70;
  8. int o3 = 031; // int 03 =  25;
  9. int o4 = 020; // int 04 = 16;
  10. int o5 = 084; //error: invalid digit "8" in octal constant int o5 = 084;
  11.  
  12. std::cout<<"Octal numbers o1 is: "<<o1<<std::endl;
  13. std::cout<<"Octal numbers o2 is: "<<o2<<std::endl;
  14. std::cout<<"Octal numbers o3 is: "<<o3<<std::endl;
  15. std::cout<<"Octal numbers o4 is: "<<o4<<std::endl;
  16.  
  17. return  0;
  18. }


Hexadecimal literals

Hexadecimal literals can be declared by prefixing them with 0x or 0X:

  1. #include<iostream>
  2.  
  3. int main ()
  4. {
  5.  
  6. int h1 = 0x42; //int h1 = 66;
  7. int h2 = 0xfa; //int h2 = 250;
  8. int h3 = 0XA; //int h3 = 10;
  9. int h4 = 0XB; //int h4 = 11;
  10. int h5 = 0x0; //int h5 = 0;
  11. int h6 = 0x1; //int h6 = 1;
  12.  
  13. std::cout<<"Hexadecimal number h1 is: "<<h1<<std::endl;
  14. std::cout<<"Hexadecimal number h2 is: "<<h2<<std::endl;
  15. std::cout<<"Hexadecimal number h3 is: "<<h3<<std::endl;
  16. std::cout<<"Hexadecimal number h4 is: "<<h4<<std::endl;
  17. std::cout<<"Hexadecimal number h5 is: "<<h5<<std::endl;
  18. std::cout<<"Hexadecimal number h6 is: "<<h6<<std::endl;
  19.  
  20. return  0;
  21. }


Binary literals

C++14 introduces binary literals which are prefixed by 0b or 0B:

  1. #include<iostream>
  2.  
  3. int main ()
  4. {
  5.  
  6. int b1 = 0b11111010; // int b1 = 250;
  7. int b2 = 0b010000111; // int b2 = 135;
  8. int b3 = 0b0100000111; // int b3 = 263;
  9. int b4 = 0B01001100110011; // int b4 = 4915;
  10. int b5 = 0B010011; // int h5 = 19;
  11.  
  12. std::cout<<"Binary number b1 is: "<<b1<<std::endl;
  13. std::cout<<"Binary number b2 is: "<<b2<<std::endl;
  14. std::cout<<"Binary number b3 is: "<<b3<<std::endl;
  15. std::cout<<"Binary number b4 is: "<<b4<<std::endl;
  16. std::cout<<"Binary number b5 is: "<<b5<<std::endl;
  17.  
  18. return  0;
  19. }


Separating literals with apostrophes

To improve readability of long literals, C++14 allows separation of digits with apostrophes:

  1. #include<iostream>
  2.  
  3. int main ()
  4. {
  5.  
  6. long d = 6'546'687'616'861'129l;
  7. int b = 0b101'1001'0011'1010'1101'1010'0001;
  8. unsigned long ulX = 0x139'ae3b'2ab0'94f3;
  9. const long double pi = 3.141'592'653'589'793'238'462l;
  10.  
  11. std::cout<<"The numbers are; " "\n";
  12. std::cout<<"Long: "<<d<< "\n"
  13. <<"Integer: "<<b<<"\n"
  14. <<"Unsigned long: "<<ulX<<"\n"
  15. <<"Constant pi: "<<pi<<"\n"<<std::endl;
  16.  
  17. return 0;
  18. }


String Literals

String literals can be typed as arrays of char. However, we can better and conveniently work with strings using string type from the library <string> . With this approach, long text can be split into multiple sub-strings.

  1. #include<iostream>
  2. #include<string>
  3.  
  4. int main ()
  5. {
  6.  
  7. char s[] = "Array of Characters"; // String as array of characters, Old C style
  8.  
  9. std::string s1 = "Better way to work with strings";
  10.  
  11. std::string s2 = "This is part one of a long text; "
  12.                  "here is the second part.";
  13.  
  14. std::cout<<"Index the first string: "<<s[0]<<"\n"
  15. <<"The second string: "<<s1<<"\n"
  16. <<"The longest string: "<<s2<<std::endl;
  17.  
  18. return 0;
  19. }


Non-narrowing Initialization

Sometimes very long values, e.g., const long double pi = 3.141'592'653'589'793'238'462l; may be printed with the leading bits cut off. To prevent this, C++11 introduces an initialization that makes sure no data is lost, i.e., values are not narrowed. This is achieved with the Uniform Initialization or Braced Initialization. If the variable can hold the value on the target architecture, values in the braces cannot be narrowed. In this case, values do not lose precision on initializations provided that they are representable with the declared types.

  1. #include<iostream>
  2. #include<string>
  3.  
  4. int main ()
  5. {
  6.  
  7. long l1 = 1234567890123;
  8. long l2 = {1234567890123};
  9.  
  10. std::cout<<"This number "<<l1<<" may be narrowed,""\n"
  11. <<"but this one "<<l2<<" cannot."<<std::endl;
  12.  
  13. return 0;
  14. }


Scopes

Scopes determine the lifetime and visibility of (non-static) variables and constants and contribute to establishing a structure in C++ programs.

Non-static variable is like a local variable and they can be accessed through only instance of a class. A static member variable of a class is shared between instances of the class. In other words, it doesn’t belong to any instance. A static variable defined in a function is only accessible in the function, but persists across function calls.


Global definition

Every variable used in a C++ program must have been declared with its type specifier at an earlier point in the code. A variable may either have the global or local scope. A global variable is declared outside all functions. After their declaration, global variables can be referred to from anywhere in the code, even inside functions. It is not advised to use global variables as it may become very difficult to track them, especially as your code grows.

Local definition

A local variable is declared within the body of a function. Its visibility/availability is limited to the enclosed block, { } of its declaration. The scope of a variable starts with its declaration and ends within the closing brace of the declaration block. In the example below, the definition of \(\pi\) is limited to the block { } within the function, and an output outside the block {} but within the function is outside the scope and will thus cause an error:

  1. #include<iostream>
  2.  
  3. int main ()
  4. {
  5.  
  6. {
  7. const double pi = 3.14159265358979323846264338327950288419716939;
  8. std::cout<<" pi is "<<pi<<".\n";
  9. }
  10. //This will cause an error
  11. std::cout<<"pi is "<<pi<<".\n"; // error: ‘pi’ was not declared in this scope
  12. }


Hiding

When a variable with the same name exists in nested scopes, then only one variable is visible. The variable in the inner scope hides the other variables with the same name in the outer scopes. Run the code below to see various scopes for the variable a:

  1. #include<iostream>
  2.  
  3. int main ()
  4. {
  5.     int a = 5; // Define a #1
  6.     std::cout<<"The value of a#1 is: "<<a<<std::endl;
  7.     {
  8.         a = 3; // Re-assign a #1, a #2 is not declared yet
  9.         int a; // Declare a #2
  10.         a = 8; // Assign a #2 , a #1 is hidden
  11.         std::cout<<"The value of a#2 is: "<<a<<std::endl;
  12.         {
  13.             a= 7; // Re-assign a #2
  14.             std::cout<<"The value of a#2 is: "<<a<<std::endl;
  15.         }
  16.     }       // End of a #2 scope
  17.     a = 11; // Re-assign a #1 (a #2 out of scope)
  18.     std::cout<<"The value of a#1 is: "<<a<<std::endl;
  19.  
  20. return 0;
  21. }


Hiding causes variables to have a distinguished lifetime and the visibility. In an example above, a #1 lives from its declaration until the end of the main function. However, it is only visible from its declaration until the declaration of a #2 and again after closing the block containing a #2. In fact, the visibility is the lifetime minus the time when it is hidden. Unfortunately, the hiding makes the homonymous variables in the outer scope inaccessible.

Static variables live till the end of the execution but are only visible within the scope.


Subprograms (Functions)

A function is a subprogram that may be reused in different parts of the program. Functions reduce verbosity and help in structuring the code. Usually, functions have a name, zero or more arguments with a fixed type, and a return type. The special return type void indicates a function that doesn’t return anything.

Example

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. // Expects one double argument, returns double
  5. double square (double x)
  6. {
  7. return x * x;
  8. }
  9.  
  10. // Expects an int and a double as arguments (args), returns nothing
  11.  
  12. void printSquares(int a = 10, float b = 20)
  13. {
  14. std::cout << square(a) << " and " << square(b) << std::endl;
  15. }
  16.  
  17. int main()
  18. {
  19. printSquares(1, 1);
  20. printSquares(30, 40.123);
  21. printSquares(100, 100.10);
  22. printSquares(30, 40.123);
  23. }


Call by Reference

C++ is one of the languages that always create copies of arguments when a function is called (call-by-value). This means that local changes to these variables don’t modify the original values. In some cases, the local names refer to the actual memory locations that were passed to the function (call-by-reference). In C++, one can pass a pointer or reference instead.

Call-by-reference is also often used when a function should return more than one value: one emulates this by modifying one or more reference arguments. For large entities (e.g., vectors, matrices) it often makes sense to pass them by reference even if they should not be modified, since this avoids costly copy operations (both in terms of runtime and memory use).

References

  1. #include <iostream>
  2.  
  3. int main (){
  4.  
  5. int a = 5;
  6. std::cout<<"Print a: "<<a<<"\n";
  7.  
  8. int& b = a; // b is an alias for a
  9. b = 4; // this changes a as well
  10. std::cout<<"Print b: "<<b<<"\n";
  11. std::cout<<"Print a: "<<a<<"\n";
  12. }


Pointers

Each type T, whether built-in or user-defined, has an associated type T* (pointer to T ) defined, with the meaning the “address of a value of type T in
memory”.

An ampersand & in front of a variable produces its address, while an asterisk * in front of a pointer dereferences the pointer, providing access to the variable itself. The keyword new can be used to acquire a slot in memory that is unnamed, i.e., not associated with a variable.

Example

  1. #include <iostream>
  2.  
  3. int main (){
  4.  
  5. int i = 5;
  6. int* p = &i; // Pointer
  7.  
  8. std::cout<<"Print i: "<<&p<<"\n"; // Obtain address
  9. std::cout<<"Print i: "<<*p<<"\n"; /* Dereference the pointer, providing access to the variable itself. */
  10.  
  11. int* p2 = new int;
  12. std::cout<<"Print p2: "<<&p2<<"\n";
  13. std::cout<<"Print p2: "<<*p2<<"\n";
  14.  
  15. *p2 = 4;
  16. std::cout<<"Print p2: "<<&p2<<"\n";
  17. std::cout<<"Print p2: "<<*p2<<"\n";
  18.  
  19. delete p2;
  20. std::cout<<"Print p2: "<<&p2<<"\n";
  21. std::cout<<"Print p2: "<<*p2<<"\n";
  22. }


Function Templates

Often, one has to define the same functionality for several different data types. This can become tedious, both during initial implementation and when fixing bugs. C++ provides a language feature for this, where all the different versions are auto-generated from a special construct, called a function template.

Example

  1. #include<iostream>
  2.  
  3. template<typename T>
  4.  
  5. T square(T x)
  6. {
  7. return x * x;
  8. }
  9.  
  10. /*
  11. A function square<T> is then available
  12. for any type T that has a multiplication operator *
  13. */
  14.  
  15. int main()
  16. {
  17. int i = square<int>(5); // int version
  18. float f = square<float>(27.f); // float version
  19. double d = square<double>(3.14); // double version
  20.  
  21. std::cout<<"Print i: "<<i<<"\n";
  22. std::cout<<"Print f: "<<f<<"\n";
  23. std::cout<<"Print d: "<<d<<"\n";
  24. }


Data Type Templates

Function definitions aren’t the only use case for templates. One can also automate the generation of data types. These are known as class templates since structs are a special case of classes in C++. Function templates and class templates were the only types of templates until C++14, when – variable templates were introduced.


Example of data type templates

  1. template<typename T>
  2. struct Pair {T a; T b;};
  3.  
  4. int main() {
  5. Pair<int> ip; // A pair of ints
  6. Pair<float> fp; // A pair of floats
  7. // Pair<int> is a data type, and can be used as such
  8. Pair<Pair<int>> ipp; // Pair of pair of ints
  9. }


Classes/Methods

The original name of C++ was “C with classes”, so classes, objects, and object-oriented programming are clearly an important part of C++.
While a classic C struct is simply an aggregation of data, C++ structs and classes typically contain methods, functions that are closely linked to the data members and parts of their type definition. A class in C++ is the building block that leads to Object-Oriented programming -- a blueprint for creating OOP or objects. We can simply define a class as a user-defined data-type which serves as a blueprint for creating objects. The class contains at least one access specifier, and holds its own data members (data variables) and member functions (user-defined data types), which can be accessed and used by creating an instance of that class.

A class in C++ is defined using keyword class followed by the name of the class (Diagram taken from here):

Image


Objects Declaration

An object is an instance (each realized variation of that object) of a class. During class definition, no memory is allocated until the class is instantiated (i.e. an object is created).

When a class is defined, only the specification for the object is defined without memory or storage allocation. To use the data and access functions defined in the class, you need to create objects. The data members and member functions of a class can be accessed using the dot operator with the object. Although public members are accessed as previously explained, the private data members are not allowed to be accessed directly by the object. Accessing a data member depends on the access control of that data member. The access control is given by Access modifiers in C++. There are three access modifiers, namely, public, private, and protected.

Example of a class

  1. // C++ program demonstrating data members access
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4.  
  5. class Names
  6. {
  7.     // Access specifier
  8.     public:
  9.  
  10.     //Declare data Members
  11.     string myName;
  12.  
  13.     // Member Functions()
  14.     void printname()
  15.     {
  16.     cout << "My name is " << myName<<"\n";
  17.     }
  18. }; // A class definition ends with semicolon
  19.  
  20. int main() {
  21.  
  22.     // Declare objects of class Names
  23.     Names obj1;
  24.     Names obj2;
  25.  
  26.     // Access data member
  27.     obj1.myName = "Mishaeli";  // Class instance/create object
  28.     obj2.myName = "Hamisi";
  29.  
  30.     // Access member function
  31.     obj1.printname();
  32.     obj2.printname();
  33.     return 0;
  34. }


Member functions can be defined inside or outside the class definition.

To define a member function outside the class definition requires scope resolution :: operator along with class name and function name:

  1. // Demonstrating function declaration outside class
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4.  
  5. class Names
  6. {
  7.     public:
  8.     string myName;
  9.     string myID;
  10.    
  11.     // printname defined inside class definition
  12.     void printname();
  13.    
  14.     // printid defined inside class definition
  15.     void printid()
  16.     {
  17.         cout << "My ID is " << myID<<"\n";
  18.     }
  19. };
  20.  
  21. /* Definition of printname outside class
  22. definition using scope resolution operator:: */
  23.  
  24. void Names::printname()
  25. {
  26.     cout << "My name is " << myName<<"\n";
  27. }
  28.  
  29. int main() {
  30.    
  31.     Names obj1;
  32.     Names obj2;
  33.    
  34.     obj1.myName = "Jesca";
  35.     obj2.myName = "Miguel";
  36.    
  37.     obj1.myID= "1512367TRE";
  38.     obj2.myID= "XDT12905634";
  39.    
  40.     // Call printname()
  41.     obj1.printname();
  42.     obj2.printname();
  43.     cout << endl;
  44.    
  45.     // Call printid()
  46.     obj1.printid();
  47.     obj2.printid();
  48.     return 0;
  49. }


Constructors

Constructors are special class members which are called by the compiler every time an object of that class is instantiated. Constructors have the same name as the class and maybe defined inside or outside the class definition. There are 3 types of constructors, namely Default constructors, Parameterized constructors, and Copy constructors. A Copy Constructor creates a new object, which is an exact copy of the existing object. The compiler provides a default Copy Constructor to all the classes.

Example of constructors

  1. // C++ program to demonstrate constructors
  2.  
  3. #include <bits/stdc++.h>
  4. using namespace std;
  5. class Names
  6. {
  7.     public:
  8.     string myID;
  9.    
  10.     //Default Constructor
  11.     Names()
  12.     {
  13.         cout << "Calling default Constructor" << endl;
  14.         myID="URTD123";
  15.     }
  16.    
  17.     // Parameterized Constructor
  18.     Names(string x)
  19.     {
  20.         cout << "Calling parameterized Constructor" << endl;
  21.         myID=x;
  22.     }
  23.    
  24.     //Copy constructors
  25.     Names (Names &){}
  26. };
  27.  
  28. int main() {
  29.    
  30.     // obj1 will call Default Constructor
  31.     Names obj1;
  32.     cout << "My ID is: " <<obj1.myID<< endl;
  33.    
  34.     // obj2 will call Parameterized Constructor
  35.     Names obj2("CDTRE3452");
  36.     cout << "My ID is: " <<obj2.myID << endl;
  37.     return 0;
  38. }


Destructors

Destructor is a special member function that is called by the compiler when the scope of the object ends.


Classes and Dot (.) Operator

Consider a class complex:

  1. #include<iostream>
  2. class complex
  3. {
  4.     public : //Public data members
  5.       double r , i;
  6. };
  7.  
  8. int main()
  9. {
  10.  
  11. complex z , c; //Create objects
  12.  
  13. z . r = 3.5; z.i = 2;
  14. c . r = 2; c . i = - 3.5;
  15. std::cout<<"z is ("<< z.r<<", " << z.i << ")\n";
  16. }


This code above defines the objects z and c with variable declarations, in the same way we declare intrinsic types -- a type name followed by a variable name or a list of names. The members of an object can be accessed with the dot operator/notation as illustrated above.


Accessibility

Each member of a class has a specified Accessibility. C ++ provides three of them:
  • public: Accessible from everywhere.
  • protected: Accessible in the class itself and its derived classes.
  • private: Accessible only within the class.
The accessibility of class members is controlled by Access Modifiers. An access modifier applies to all following members until another modifier appears. Class members before the first modifier are all private.

Struct

C++ has the struct keyword from C which declares a class as well, with all features available for classes. The only difference is that all members are by default public.

Therefore, in C++

  1. struct xyz
  2. {
  3.     ...
  4. };


is the same as:

  1. class xyz
  2. {
  3.     public:
  4.         ...
  5. };


Access Operators

We have seen that we can select the member of a class by using the dot (.) operator. The rest of the access operators are pointer-related in some way.
Let us consider a pointer to the class complex and how to access member variables through this pointer:

  1. #include<iostream>
  2. class complex
  3. {
  4.     public :  // Public data members
  5.       double r , i;
  6. };
  7.  
  8. int main()
  9. {
  10.  
  11. complex c ;
  12.  
  13. //Pointers to the class complex
  14. complex* p = &c;
  15.  
  16. //* p . r = 3.5; // This will cause error, it requires *( p.r)
  17. (*p).r = 3.5;
  18. p->r = 3.5;
  19. }


But, accessing members through pointers is not favoured since the dot operator has a higher priority than the dereference *.


Abstraction using Classes

Class helps us to group data members and member functions/methods using available access specifiers. A Class can decide which data member will be visible to outside world and which is not.

In the program below, we are not allowed to access the variables a and b directly, however, we can call the function indirect_access() to set the values a and b and and print them:

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. class abstract
  5. {
  6. private:
  7.     int a, b;
  8.  
  9. public:
  10.  
  11. //set values of the private members
  12. void Indirect_Access(int x, int y) //Public method
  13.     {
  14.     a = x;
  15.     b = y;
  16.  
  17.     cout<<"a = " <<a <<" and "
  18.     <<"b = " << b << endl;
  19.     }
  20.  
  21. };
  22.  
  23. int main()
  24. {
  25.     abstract obj;
  26.     obj.Indirect_Access(678, 758);
  27.     return 0;
  28. }


Recommended IDEs

KDevelop (best for Linux), Eclipse, Visual Studio, and Code::Blocks (a free, open-source cross-platform IDE that supports multiple compilers including GCC, Clang and Visual C++).


References

1. Discovering Modern C++: An Intensive Course for Scientists, Engineers, and Programmers (C++ In-Depth Series), Addison-Wesley Professional; First Edition (December 17, 2015)
1
1 Image
TSSFL -- A Creative Journey Towards Infinite Possibilities!
User avatar
Eli
Senior Expert Member
Reactions: 183
Posts: 5334
Joined: 9 years ago
Location: Tanzania
Has thanked: 75 times
Been thanked: 88 times
Contact:

#2

0
TSSFL -- A Creative Journey Towards Infinite Possibilities!
User avatar
Eli
Senior Expert Member
Reactions: 183
Posts: 5334
Joined: 9 years ago
Location: Tanzania
Has thanked: 75 times
Been thanked: 88 times
Contact:

#3

C++ Programming Practicals

for loop

  1. #include <iostream>
  2.  
  3. int main () {
  4.  
  5. for (int i = 0; i < 10; i++)
  6.     std::cout << i << std::endl;
  7.  
  8. return 0;
  9. }

II. for loop (and a dimensional array)

  1. #include<iostream>
  2. #include<string>
  3.  
  4. using namespace std;
  5. int main ()
  6. {
  7.  
  8. const int rows = 6;
  9. const int cols = 6;
  10. int Total = 0;
  11. double average = 0.0;
  12. int grades[rows][cols] = {{89, 98, 78, 79, 100, 96},    //initialization of 6 by 6 array
  13.                       {97, 87, 77, 80,90, 95},
  14.                       {86, 88, 99, 94, 92, 84},
  15.                       {75, 85, 81, 83, 98, 90},
  16.                       {80, 76, 77, 89, 96, 77},
  17.                       {90,80,78,91, 93, 100}};
  18.                      
  19. for (int r = 0; r < rows; ++r) {cout<<"Students "<<r+1<<" Marks"<<": ";
  20.                            for (int c = 0; c < cols; ++c){
  21.                            cout<<grades[r][c]<<" ";
  22.                            Total += grades[r][c];
  23.                            }
  24.                              
  25.                      average = Total/cols;
  26.                      cout<<"Average is "<<average<<endl;
  27.                      Total = 0;
  28.                      average = 0.0;  
  29.                  }  
  30. return 0;
  31. }

while loop

I.

  1. #include <iostream>
  2.  
  3. int main () {
  4.  
  5. int j = 9;
  6.  
  7. while (j > 1)
  8.    {
  9.    std::cout << j << std::endl;
  10.    j /= 2; // Half rounded
  11.    }
  12.  
  13. return 0;
  14. }

II.

  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. int main() {
  6.    
  7. int i = 1;
  8.  
  9.     // while loop from 1 to 5
  10.     while (i <= 5) {
  11.         cout << i << ", "<<"\n";
  12.         ++i;
  13.        
  14.     }
  15. return 0;
  16. }

III.

  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. int main() {
  6.    
  7. int number;
  8. int sum = 0;
  9.  
  10. //Take input from the user
  11. cout << "Enter a number: ";
  12. cin >> number;
  13.  
  14. while (number >= 0) {
  15.     //Add all positive numbers
  16.     sum += number;
  17.  
  18.     //Take input again if the number is positive
  19.     cout << "Enter a number: ";
  20.     cin >> number;
  21. }
  22.  
  23. //Display the sum
  24. cout << "\nThe sum is " << sum << endl;
  25.  
  26. return 0;
  27. }

if statement

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main () {
  5.  
  6. int n , m; // Declare n and m to be integers
  7.  
  8. cout <<"Enter two integers : \n"; // Output to screen
  9.  
  10. cin >> n >> m; // Inputs will be assigned to n, m
  11.  
  12. if (n > m ) { // If n is bigger than m, swap them
  13.  
  14. int temp = n ; // Declare temp and initialize it
  15. n = m; // Assign value of m to n
  16. m = temp;  // Assign value of temp to m
  17. }
  18.  
  19. cout<< " m has the value of: " << m <<"\n";
  20.  
  21. return 0;
  22. }

for and if loops

  1. #include<iostream>
  2.  
  3. using namespace std;
  4.  
  5. int main ()
  6. {
  7. for (int i = 1; i<= 100; i++) if (i%5==0) cout<<"i = "<<i<<endl;
  8. return 0; //Terminate the program
  9. }

if else

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main() {
  5.   int n;
  6.  
  7.   cout << "Enter an integer: ";
  8.   cin >> n;
  9.  
  10.   if ( n % 2 == 0)
  11.     cout << n << " is even.";
  12.    
  13.   else if ( n % 2 != 0)
  14.     cout << n << " is odd.";
  15.  
  16.   return 0;
  17. }

if, else if, else

  1. // Program to check whether an integer is positive, negative or zero
  2. #include <iostream>
  3. using namespace std;
  4.  
  5. int main() {
  6.  
  7.     int number;
  8.  
  9.     cout << "Enter an integer: ";
  10.     cin >> number;
  11.    
  12.     if (number > 0) {
  13.         cout << "You entered a positive integer: " << number << endl;
  14.     }
  15.  
  16. else if (number < 0) {
  17.       cout << "You entered a negative integer: " << number << endl;
  18.      }
  19.  
  20. else {
  21.         cout << "You entered 0" << endl;
  22.     }
  23.      cout << "This line is always printed";
  24.     return 0;
  25. }

Jump statements, continue and break

  1. #include <iostream>
  2.  
  3. int main (){
  4.  
  5. /* The continue statement can be used to skip the rest of the current loop
  6. iteration, while break exits the loop prematurely: */
  7.  
  8. for (int i = 0; i < 100; i++)
  9. {
  10.  
  11. if (i%2 == 0)
  12.   continue;
  13.  
  14. if (i > 10)
  15.     break;
  16.    
  17. // prints 1, 3, 5, 7, 9
  18. std::cout << i << std::endl;
  19. }
  20.  
  21. return 0;
  22. }

switch statement

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main () {
  5. //Local variable declaration:
  6. char grade;
  7.  
  8. cin >> grade;
  9.    
  10. switch(grade) {
  11.       case 'A' :
  12.          cout << "Excellent!" << endl;
  13.          break;
  14.       case 'B' :
  15.       case 'C' :
  16.          cout << "Well done" << endl;
  17.          break;
  18.       case 'D' :
  19.          cout << "You passed" << endl;
  20.          break;
  21.       case 'F' :
  22.          cout << "Better try again" << endl;
  23.          break;
  24.       default :
  25.          cout << "Invalid grade" << endl;
  26.    }
  27.    
  28.    //cout<<" Please Enter grade: "<<endl;
  29.    cout << "Your grade is " << grade << endl;
  30.  
  31.    return 0;
  32. }

Functions

  1. // my first program in C++
  2.  
  3. #include <iostream>
  4. using namespace std;
  5.  
  6. double square(double x) // Square a double precision floating-point number
  7. {
  8.  
  9. return x*x;
  10. }
  11.  
  12. void print_square(double x)
  13. {
  14. cout<<"The square of "<<x<<" is "<<square(x)<<'\n';
  15. }
  16.  
  17. int main()
  18. {
  19. print_square(100.10);
  20. print_square(40.123);
  21. }

Arrays

A. C-style fixed-length array

Arrays and range-based for loop

C++11 range-based for loop works with C-style arrays, but only for those with compile-time fixed length; doesn’t work when the length is runtime-dependent!

I.

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. int main(){
  6.    
  7. // C-style fixed-length array
  8. int fix[10] = {0,1,2,3,4,5,6,7,8,9};
  9.  
  10. /*Printing array elements
  11. using range based for loop*/
  12. for (const auto& x : fix)
  13.     if (x % 2 == 0)
  14.         cout << x << " \n";
  15. cout <<endl;
  16.  
  17. return 0;
  18. }


II.

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main() {
  5. int numbers[5] = {7, 5, 6, 12, 35};
  6.  
  7. cout << "The numbers are: ";
  8.  
  9. /* Printing array elements
  10. using range based for loop */
  11.  
  12. for (int n: numbers) {
  13.   cout << n << ",  ";
  14.   }
  15.  
  16. return 0;
  17. }

III.

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main() {
  5. int numbers[5] = {7, 5, 6, 12, 35};
  6.  
  7. cout << "The numbers are: ";
  8.  
  9. /* Printing array elements
  10. using range based for loop */
  11.  
  12. for (const int n: numbers) {
  13.   cout << n << ",  ";
  14.   }
  15.  
  16. return 0;
  17. }


IV.

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main() {
  5. int numbers[5] = {7, 5, 6, 12, 35};
  6.  
  7. cout << "The numbers are: ";
  8.  
  9. /* Printing array elements
  10. using range based for loop */
  11.  
  12. for (const int &n: numbers) {
  13.   cout << n << ",  ";
  14.   }
  15.  
  16. return 0;
  17. }

Arrays and traditional for/while loop

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main() {
  5. int numbers[5] = {7, 5, 6, 12, 35};
  6.  
  7. cout << "\nThe numbers are: \n";
  8.  
  9. int i =0, sum = 0;
  10.  
  11. /* Printing array elements using traditional for loop
  12. A loop, i changes from 0 to 1, 2, 3, 4 with increment of 1 each time */
  13. //for (i; i< 5; i++)
  14. while (i< 5) {
  15.   cout << numbers[i] << "  " "\n";
  16.   sum = sum + numbers[i];
  17.   i = i + 1;
  18.   }
  19. cout << sum << "  ";
  20. return 0;
  21. }

B. C++ variable-length array

I.

  1. #include <bits/stdc++.h>
  2.  
  3. int main(){
  4.    
  5. int n = 100;
  6.  
  7. /* C++ variable-length array
  8. Elements can be added and removed */
  9.  
  10. std::vector<int> var(n); // A true/real variable-length array
  11.  
  12. //C++11 fill, requires <numeric>
  13. std::iota(var.begin(), var.end(),0);
  14.  
  15. //C++11: range-based for loop
  16.  
  17. for (const auto& i : var)
  18.     if (i % 2 == 0)
  19.         std::cout << i << " ";
  20. std::cout << std::endl;
  21.  
  22. return 0;
  23. }

II.

  1. #include <bits/stdc++.h>
  2.  
  3. int main(){
  4.    
  5. int n = 10;
  6. int* var = new int[n];
  7.  
  8. for (int i = 0; i < n; i++){
  9.    var[i] = i;
  10.    std::cout<<var[i]<<std::endl;
  11. }
  12.  
  13. /* "var" isn't a real variable-length array:
  14. Adding elements requires copying */
  15.  
  16. // "var" doesn't know its own size
  17. for (int i = 0; i < n; i++)
  18.     if (var[i] % 2 == 0)
  19.         std::cout << var[i] << ", ";
  20. std::cout << std::endl;
  21.  
  22. return 0;
  23. }


C. C++11 modern array type

  1. #include <bits/stdc++.h>
  2. #include<array>
  3.  
  4. int main(){
  5.    
  6. //C++11: modern array type from header <array>
  7.  
  8. std::array<int,10> fix = {0,1,2,3,4,5,6,7,8,9};
  9.  
  10. //No need to remember size of "fix"
  11.  
  12. for (int i = 0; i < fix.size(); i++)
  13.     if (fix[i] % 2 != 0)
  14.         std::cout << fix[i] << ", ";
  15. std::cout << std::endl;
  16.  
  17. return 0;
  18. }


Vectors

I. A vector with n constant values

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. int main()
  5. {
  6.  int n = 5;
  7.  
  8. // Create a vector of size n with all values as 10
  9.  
  10. vector<int> vec(n, 10);
  11.  
  12. cout<< "Print components of a vector of size n:" <<endl;
  13.  
  14. for (int x : vec)
  15.     cout << x << " " "\n";
  16.    
  17. return 0;
  18. }

II. Vector initialized as an array

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. int main(){
  6.    
  7. //Initialize a vector like an array
  8.  
  9. vector<int> vec{ 10, 20, 30, 40, 50};
  10.  
  11. cout<< "Print components of a vector initialized as an array:" <<endl;
  12.  
  13. for (int x : vec)
  14.     cout << x << " " "\n";
  15.    
  16. return 0;
  17. }

III. Initialize a vector from an array

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. int main(){
  6.    
  7. //Initialize a vector from array
  8. int arr[] = { 10, 20, 30, 40, 50, 60};
  9.  
  10. int n = sizeof(arr) / sizeof(arr[0]);
  11.  
  12. vector<int> vec(arr, arr + n);
  13.  
  14. cout<<"Print vector components initialized from array:" <<endl;
  15.  
  16. for (int x : vec)
  17.         cout << x << " " "\n";
  18.    
  19. return 0;
  20. }

IV. Initialize a vector from another vector

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. int main(){
  6.    
  7. //Initialize a vector from another vector
  8.  
  9. vector<int> vec1{ 10, 20, 30, 40, 50, 60, 70};
  10.  
  11. vector<int> vec2(vec1.begin(), vec1.end());
  12.  
  13. cout<< "Print components of a vector initialized from another vector:" <<endl;
  14. for (int x : vec2)
  15.         cout << x << " " "\n";
  16.  
  17. return 0;
  18. }

V. Initialize a vector with particular value

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. int main(){
  6.    
  7. //Initialize a vector with particular value
  8.  
  9. vector<int> vec(10);
  10. int value = 100;
  11.    
  12. fill(vec.begin(), vec.end(), value);
  13.  
  14. cout<< "Print vector components for a vector initialized with a particular value:" <<endl;
  15.  
  16. for (int x : vec)
  17.         cout << x << " " "\n";
  18.  
  19. return 0;
  20. }

Vector and push_back() function

  1. #include <bits/stdc++.h>
  2.  
  3. int main(){
  4.    
  5. std::vector<int> my_vector{ 1, 2, 3, 4, 5};
  6. my_vector.push_back(9);
  7.  
  8. //Vector becomes 1, 2, 3, 4, 5, 9
  9.  
  10. for (auto v = my_vector.begin(); v != my_vector.end(); ++v)
  11.     std::cout <<*v<<' ';
  12. std::cout << std::endl;
  13.  
  14. return 0;
  15. }

A very general vector implementation

  1. #include <bits/stdc++.h>
  2.  
  3. int main(){
  4.  
  5. int n = 10;
  6.  
  7. std::vector<int> var(n);
  8. for (int i = 0; i < n; i++)
  9.     var[i] = i;
  10.  
  11. var.push_back(n+1);
  12.  
  13. //Very general array (also works for maps, sets, lists, ...)
  14. for (std::vector<int>::const_iterator t = var.begin(); t != var.end(); ++t)
  15.     if (*t % 2 == 0)
  16.        std::cout << *t << " \n";
  17. std::cout << std::endl;
  18.  
  19. return 0;
  20. }

C++11 lambda expression

  1. #include <bits/stdc++.h>
  2.  
  3. int main(){
  4.    
  5. // C++11: lambda expression
  6.  
  7. auto even = [](int i){return i % 2 == 0;};
  8.     std::cout << even << " ";
  9. std::cout << std::endl;
  10.  
  11. return 0;
  12. }

References

I.

  1. #include <iostream>
  2.  
  3. int main (){
  4.  
  5. int a = 5;
  6. std::cout<<"Print a: "<<a<<"\n";
  7.  
  8. int& b = a; // b is an alias for a
  9. b = 100; // this changes a as well
  10.  
  11. std::cout<<"Print b: "<<b<<"\n";
  12. std::cout<<"Print a: "<<a<<"\n";
  13. }

Pointers

  1. #include <iostream>
  2.  
  3. int main (){
  4.  
  5. int i = 5;
  6. int* p = &i; // Pointer
  7.  
  8. std::cout<<"Print i: "<<&p<<"\n"; // Obtain address
  9. std::cout<<"Print i: "<<*p<<"\n"; /* Dereference the pointer, providing access to the variable itself. */
  10.  
  11. int* p2 = new int;
  12. std::cout<<"Print p2: "<<&p2<<"\n";
  13. std::cout<<"Print p2: "<<*p2<<"\n";
  14.  
  15. *p2 = 4;
  16. std::cout<<"Print p2: "<<&p2<<"\n";
  17. std::cout<<"Print p2: "<<*p2<<"\n";
  18.  
  19. delete p2;
  20. std::cout<<"Print p2: "<<&p2<<"\n";
  21. std::cout<<"Print p2: "<<*p2<<"\n";
  22. }

Constant Pointers

  1. #include <iostream>
  2.  
  3. int main (){
  4.  
  5. int i = 5; // May change later on
  6. const int j = 4; // Guarantedd to stay 4
  7. const int& k = i; // k can't be modified
  8. i += 2;           // ... but this still changes k indirectly!
  9.  
  10. const int* p1 = &i; // Pointer to const int
  11. int const* p2 = &i; // Same thing
  12. int* const p3 = &i;  // Constant pointer to modifiable int
  13. int const* const p4 = &i; // Const pointer to const int
  14.  
  15. }

Exercise

Write the following C program in a standard C++ to find the total number of elements in an array that are greater than all elements to their right. Exclude the last digit since there is no element to its right.

  1. #include <stdio.h>
  2. #include <limits.h>
  3.  
  4. /* Function to print all elements which are greater than all
  5.  elements present to their right */
  6.  
  7. /*The idea is to traverse the array from right to left and maintain a variable
  8. that stores the maximum element encountered so far. So if the current element
  9. is greater than the maximum so far, print the current element and update
  10. the maximum so far. This approach is demonstrated below in C */
  11.  
  12. void find(int arr[], int n)
  13. {
  14.    
  15. int curr_max = INT_MIN;
  16.  
  17. //Traverse the array from right to left
  18. for (int i = n-1; i >= 0; i--){
  19.  
  20. /* if the current element is greater than the current maximum (curr_max),
  21. print it and update 'curr_max' */
  22.  
  23. if (arr[i] >= curr_max){
  24.     curr_max = arr[i];
  25.     printf("%d ", arr[i]);
  26.     }
  27. }
  28.  
  29. }
  30.  
  31. int main(void)
  32. {
  33.     int arr[] = { 10, 4, 6, 3, 5};
  34.    
  35.     int n = sizeof(arr)/sizeof(arr[0]);
  36.  
  37.     find(arr, n);
  38.  
  39. return 0;
  40. }

0
TSSFL -- A Creative Journey Towards Infinite Possibilities!
User avatar
Eli
Senior Expert Member
Reactions: 183
Posts: 5334
Joined: 9 years ago
Location: Tanzania
Has thanked: 75 times
Been thanked: 88 times
Contact:

#4

Namespace in Programming

A namespace is a logical container that defines a scope for identifiers (such as variables, functions, and classes) in a programming language.
An identifier is a unique name assigned to a variable, function, class or any other object defined in the program.

Namesoace serves the following purposes:

1. Scope and Collision Avoidance:

Namespaces create isolated spaces within a program, preventing naming collisions.
Identifiers defined within a namespace are only accessible within that namespace, avoiding ambiguity when using similar names across multiple parts of the program.

2. Organization and Structure:

Namespaces help organize code into logical modules or categories.
They improve code readability and maintainability by grouping related identifiers together.

3. Name Resolution:

When a program references an identifier, the compiler searches within the active namespace to find its definition.
If the identifier is not found in the current namespace, the compiler looks for it in the parent namespace or any other imported namespaces.

4. Code Reusability:

Namespaces allow developers to define and share common functionality across different parts of a program.
By enclosing reusable code in a namespace, it can be easily imported and used as needed.

5. Dependency Management:

Namespaces help manage dependencies between different parts of a program.
By defining dependencies as namespaces, it becomes easier to track and control their interactions.

Examples:

C++

namespace myNamespace {
int a = 10;
}

Python

from myModule import *

class MyClass:
# ...

Java

package com.example.myApp;

public class MyMainClass {
// ...
}

Benefits of Using Namespaces:

Improved code organization and readability
Reduced naming collisions
Enhanced code reusability
Better dependency management
Increased maintainability
0
TSSFL -- A Creative Journey Towards Infinite Possibilities!
Post Reply

Return to “C & C++ Programming”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 9 guests