The C++ programming language (originally named “C with Classes”) was devised by Bjarne Stroustrup — also an employee from Bell Labs (AT&T). Stroustrup started working on C with Classes in 1979. (The ++ is a C language operator.) The first commercial release of the C++ language was in October 1985.
Enforce safety at compile time:
The main goal here is to detect errors early. In C++, the compiler strictly checks your code to make sure you’re not performing illogical operations (such as trying to combine text with a number). Detecting these errors before launching the program (Compile time) prevents it from crashing suddenly while the client is using it (Run time), which is crucial for major commercial programs.
Statically Typed Language:
In C++, you must declare the type of a variable (eg int, string) before using it. Once the type is selected, it cannot be changed. This strict system is what gives the compiler the ability to verify security.
Benefits of Type Annotations:
Ease of reading the code (More readable): When another programmer looks at the code and finds the data types clearly defined, he immediately understands the purpose of each variable or function, which makes the code a documentation for itself
Improving performance and efficiency (Compiler optimizations): Since the compiler precisely knows the type and space of each statement in memory, he can optimize the source code so that it runs at the maximum possible speed and without any additional consumption of device resources during operation (unlike dynamic languages that waste part of the time to identify the type of the variable during operation).
Create custom type systems (Define own type system): The C++ language is not limited to basic types (numbers, texts), but rather gives the programmer the power and freedom to invent completely new and complex data types (such as object classes) that suit the idea of his program, while applying the same strict security rules to them.
Programming model: compartmentalization, only addition features if they solve an actual problem, and allow full control
Predictable runtime (under constraints): no garbage collector, no dynamic type system → real-time systems
Low resources: low memory and energy consumption → restricted hardware platforms
Well suited for static analysis → safety critical software
Portability → Modern C++ standards are highly portable
“C++ is for people who want to use hardware very well and manage the complexity of doing that through abstraction”
“A language like C++ is not for everybody. It is generated via sharp and effective tool for professional basically and definitely for people who aim at some kind of precision”
“C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do, it blows your whole leg off” — Bjarne Stroustrup, Creator of the C++ language
“The problem with using C++…is that there’s already a strong tendency in the language to require you to know everything before you can do anything” — Larry Wall, Creator of the Perl language
“Despite having 20 years of experience with C++, when I compile a non-trivial chunk of code for the first time without any error or warning, I am suspicious. It is not, usually, a good sign” — Daniel Lemire, Prof. at the University of Quebec
Advanced Resources
These are advanced resources for solving C++ problems after you finish the course:
The primary goal of the course is to drive who has previous experience with C/C++ and object-oriented programming to a proficiency level of C++ programming.
Proficiency: know what you are doing and the related implications
Understand what problems/issues address a given language feature
Learn engineering practices (e.g. code conventions, tools) and hardware/software techniques (e.g. semantic, optimizations) that are not strictly related to C++
What the course is:
A practical course, prefer examples to long descriptions
A “quite” advanced C++ programming language course
gcc/g++ is the default C/C++ compiler on most Linux distributions. If necessary, it can be updated manually. Follow the instructions below to update it on Ubuntu/Debian (v14):
Any C++ standard is backward compatible. For example, a code compiled with C++17 still works with C++20. C++ is built on top of C and it supports backward compatibility in simple cases. However, there are several exceptions. The most common cases are C++ keywords (new, template, class, typename, etc.) that cannot be used for symbol naming.
It is a good practice to add warning flags and sanitizers, especially for beginners, to catch potential problems in the code.
Reverse Engineering: C++ is a fundamental language for understanding and analyzing executable files (Binaries), and dealing deeply with advanced analysis tools like IDA Pro, x64dbg, and Ghidra.
Game Development: The most powerful game engines (like Unreal Engine) are written in it for complex graphics processing at high speed.
Operating Systems: Large parts of operating systems like Windows, macOS, and Linux are built with it.
Heavy Desktop Applications: Like design and editing software (Photoshop, Premiere).
Web Browsers: Popular browser engines like Google Chrome and Safari rely on it.
Let us create a blank text file using the text editor or C++ IDE of our choice and name it source.cpp. First, let us create an empty C++ program that does nothing:
1
intmain()
2
{
3
}
This simple program does nothing, it has no parameters listed inside parentheses, and there are no statements inside the function body. It is essential to understand that this is the main program signature. There is also another main function signature accepting two different parameters used for manipulating the command line arguments. For now, we will only use the first form.
In the printf function (legacy): The function does not know what type of variable it wants to print automatically. You must activate them with the variable type during the program (dynamically) using custom symbols such as %d for integers or %s for strings.
In C++ functions (such as cout): The compiler knows the type of the variable in advance (static) while writing the code. You don’t need to tell it what type of data it is, it will automatically detect it and print it for sure.
With I/O Stream, there are no redundant % tokens that have to be consistent with the actual objects passed to I/O stream. Removing redundancy removes a class of errors.
Single line comments in C++ start with double slashes // and the compiler ignores them. We use them to comment or document the code or use them as notes:
Now we are ready to get the first glimpse at our “Hello World” example. The following program is the simplest “Hello World” example. It prints out Hello World in the console window:
1
#include<iostream>
2
intmain() {
3
std::cout <<"hello world";
4
}
Explanation
The #include <iostream> statement includes the iostream header into our source file via the #include directive. The iostream header is part of the standard library. We need its inclusion to use the std::cout object, also known as a standard-output stream. The << operator inserts our “Hello World” string literal into that output stream. String literal is enclosed in double quotes "". The ; marks the end of the statement. Statements are pieces of the C++ program that get executed. Statements end with a semicolon ; in C++. The std is the standard-library namespace and :: is the scope resolution operator. Object cout is inside the std namespace, and to access it, we need to prepend the call with std::.
We can output multiple string literals by separating them with multiple << operators:
1
#include<iostream>
2
3
intmain() {
4
std::cout <<"first output "<<" second output ";
5
}
To output on a new line, we need to output a new-line character \n literal:
Let us declare a variable b of type bool. This type holds values of true and false:
1
intmain() {
2
bool b; // this has no value, default value is false == 0
3
}
How to add value:
1
intmain() {
2
bool b =true; // or
3
bool A {false};
4
}
Rule
All local variables must always be given an initial value once they are created (never leave them empty).
If you try to read or use a variable that has not been given an initial value (uninitialized), this will lead to a serious problem called undefined behavior (UB). This means that the program will lose control and may behave completely randomly (e.g., print fake values, operate unpredictably, or crash and stop working).
Is used to represent a single character. The size is 1 byte:
1
intmain() {
2
char c ='a';
3
}
To print:
1
#include<iostream>
2
3
intmain() {
4
char c ='a';
5
std::cout <<"the value of variable c is: "<< c;
6
}
Once declared and initialized, we can access our variable and change its value:
1
#include<iostream>
2
3
intmain() {
4
char c ='a';
5
std::cout <<"the value of variable c is: "<< c;
6
c ='b';
7
std::cout <<" the value of variable c is: "<< c;
8
}
The size of the char type in memory is usually one byte. We obtain the size of the type through the sizeof operator:
1
#include<iostream>
2
3
intmain() {
4
std::cout <<"the size for char is: "<<sizeof(char) <<" byte(s)";
5
}
There are other character types such as wchar_t for holding characters of Unicode character set, char16_t for holding UTF-16 character sets, but for now, let us stick to the type char. A character literal is a character enclosed in single quotes. Example: 'a', 'A', 'z', 'X', '0' etc. Every character is represented by an integer number in the character set. That is why we can assign both numeric literals (up to a certain number) and character literals to our char variable:
1
intmain() {
2
char c ='a';
3
// is the same as if we had
4
// char c = 97;
5
}
The 'a' character in ASCII table is represented with the number 97.
Fundamental type is int called integer type. We use it to store integral values (whole numbers), both negative and positive:
1
#include<iostream>
2
3
intmain() {
4
int x =123;
5
int c =-123;
6
std::cout <<"the value x is: "<< x <<'\n'<<"the value c is: "<< c;
7
}
The size of int is usually 4 bytes. We can also initialize the variable with another variable. It will receive a copy of its value. We still have two separate objects in memory:
1
#include<iostream>
2
3
intmain() {
4
int x =123;
5
int y = x;
6
std::cout <<"The value of x is: "<< x <<" ,the value of y is: "<< y;
7
// x is 123
8
// y is 123
9
x =456;
10
std::cout <<"The value of x is: "<< x <<" ,the value of y is: "<< y;
11
// x is now 456
12
// y is still 123
13
}
Programming languages (like C and C++) allow you to write numerical values in three different number systems, and the compiler understands them based on the prefix you write before the number:
Decimal: Regular numbers from 0 to 9. You write the number directly without any additions.
Octal: Numbers from 0 to 7. To tell the compiler that the number is octal, you must place a zero (0) before it.
Hexadecimal: Numbers from 0 to 9 and letters from A to F. For the compiler to understand it, you must place 0x before it.
1
intmain() {
2
int x =10; // decimal literal
3
int y =012; // octal literal
4
int z =0xA; // hexadecimal literal
5
}
All these variables have been initialized to a value of 10 represented by different integer literals. For the most part, we will be using decimal literals. There are other integer types such as int64_t and others, but we will stick to int for now.
There are three floating-point types in C++: float, double, long double, but we will stick to type double (double-precision). We use it for storing floating-point values / real numbers:
Type void is a type with no values. Well, what is the purpose of such type if we can not create objects of that type? Good question. While we can not have objects of type void, we can have functions of type void. Functions that do not return a value. We can also have a void pointer type marked with void*. More on this in later chapters when we discuss pointers and functions.
Types can have modifiers. Some of the modifiers are signed and unsigned. The signed (the default if omitted) means the type can hold both positive and negative values, and unsigned means the type has unsigned representation. Other modifiers are for the size: short — type will have the width of at least 16 bits, and long — type will have the width of at least 32 bits. Furthermore, we can now combine these modifiers.
1
#include<iostream>
2
3
intmain() {
4
unsignedlongint x =4294967295;
5
std::cout <<"The value of an unsigned long integer variable is: "<< x;
6
}
Variable Declaration, Definition, and Initialization#
1
#include<iostream>
2
3
intmain() {
4
char c ='h';
5
int x =5;
6
double d =5.2;
7
}
1
intmain() {
2
int d, e, f;
3
}
1
intmain() {
2
int x =50;
3
int y = {30};
4
int z {20};
5
}
A variable definition is setting a value in memory for a name. The definition is making sure we can access and use the name in our program. Roughly speaking, it is a declaration followed by an initialization (for variables) followed by a semicolon. The definition is also a declaration.
Write a program that declares variables inside the main function. Since we do not use any input or output, we do not need to include the <iostream> header:
Write a program that defines three variables inside the main function. The variables are of char, int, and type double. The names of the variables are arbitrary. The initializers are arbitrary.
Write a program that defines three variables inside the main function. The variables are of char, int, and type double. The names of the variables are arbitrary. The initializers are arbitrary. The initialization is performed using the initializer list. Print the values afterward.
1
#include<iostream>
2
3
intmain() {
4
char mychar {'c'};
5
int myint {225};
6
double mydouble {2.369};
7
std::cout <<" the value char is: "<< mychar <<'\n';
We can do arithmetic operations using arithmetic operators:
1
+ // addition
2
- // subtraction
3
* // multiplication
4
/ // division
5
% // modulo
1
#include<iostream>
2
3
intmain() {
4
int x =123;
5
int y =456;
6
int z = x + y; // addition
7
z = x - y; // subtraction
8
z = x * y; // multiplication
9
z = x / y; // division
10
11
std::cout <<" the value of z is: "<< z <<'\n';
12
}
The integer division, in our example, results in a value of 0. It is because the result of the integer division where both operands are integers is truncated towards zeros. In the expression x / y, x and y are operands and / is the operator. If we want a floating-point result, we need to use the type double and make sure at least one of the division operands is also of type double:
Increment/decrement operators increment/decrement the value of the object:
1
++x // pre-increment operator
2
x++ // post-increment operator
3
--x // pre-decrement operator
4
x-- // post-decrement operator
1
#include<iostream>
2
3
intmain() {
4
int x =123;
5
x++;
6
++x;
7
--x;
8
x--;
9
10
std::cout <<" the value x: "<< x;
11
}
Both pre-increment and post-increment operators add 1 to the value of our object, and both pre-decrement and post-decrement operators subtract one from the value of our object. The difference between the two, apart from the implementation mechanism (very broadly speaking), is that with the pre-increment operator, a value of 1 is added first. Then the object is evaluated/accessed in expression. With the post-increment, the object is evaluated/accessed first, and after that, the value of 1 is added. To the next statement that follows, it does not make a difference. The value of the object is the same, no matter what version of the operator was used. The only difference is the timing in the expression where it is used.
In C++, we can read input from the user using std::cin along with the extraction operator >>. This allows programs to be interactive by accepting values at runtime:
1
#include<iostream>
2
3
intmain() {
4
int x;
5
std::cout <<"Enter a number: ";
6
std::cin >> x;
7
std::cout <<"You entered: "<< x <<'\n';
8
}
We can also read multiple values:
1
#include<iostream>
2
3
intmain() {
4
int a;
5
double b;
6
std::cout <<"Enter an integer and a double: ";
7
std::cin >> a >> b;
8
std::cout <<"You entered: "<< a <<" and "<< b <<'\n';
9
}
Share
If this article helped you, please share it with others!