This is the first post of my ambitious plan trying to enumerate as many key points about the C++ language as I can. These notes are only for personal reviewing purposes and shall definitely be used commercially by anyone interested. Just please comment below for any missing C++ syntax or features. 👍🏻

Basically there're only one thing that needs attention. For standard libraries we use < and > and for local libraries we use quotes.

These are files we declare functions and classes we want to use or implement in main files.

# Standard Input & Output

In C++, by loading the iostream library we can read and write by

# Namespaces

Normally libraries come with classes, e.g. for iostream we need to use std everytime we need to print something. With namespaces we can reduce redundance.

We may also use using namespace std; which sometimes can cause problems.

# Data Types

There are a variety of data types in C++. For real numbers we have

Type Bytes Range
float $4$ $\pm 3.4E\pm38$
double $8$ $\pm 1.7E\pm308$

where we should pay enough attention to the $\pm$. For general integers we have

Type Bytes Range
short $2$ $-2E15$ to $2E15-1$
int $4$ $-2E31$ to $2E31-1$
long $8$ $-2E63$ to $2E63-1$

and for each type we also have an unsigned version that starts from 0 and covers the same length of range.

We may notice that long has a smaller range than float despite the fact that the first data type actually costs more bytes than the latter. This is because the 4 bytes (or 32 bits) of a float $V$ is not stored equally in RAM, but rather

$V = (-1)^S \cdot M \cdot 2^E$

where $S$ is the first bit, and $E$ the second through the ninth bits, and $M$ for the tenth and so forth. So in a sense, because float is more "sparse", the long type has a smaller range.

Apart from other fundamental types like char and bool, we can also define our own data types or use types defined in libraries, e.g. std::string. We may also use type aliases like

# Operators

We have operators for fundamental types:

Function Operator
assignment =
arithmetic + - * /
comparison > < <= >=
equality/nonequality == !=
logical && ||
modulo %

In C++ there're a set of short-cuts as follows:

Full Operator Short-cut
i = i + 1; i++; i += 1;
i = i - 1; i--; i -= 1;
i = i * 1; i *= 1;
i = i / 1; i /= 1;

We may also use prefix and postfix in assignment, which are totally different. After

we have $x = 4$ and $y = 3$. After

we have $x = y = 3$.

# Functions

A general template for a C++ function:

Notice we may write multiple functions with the same resType but with different arguments, which we call "parameter overloading". Meanwhile, even withou parameter overloading we can still use a function of double on int, because int takes up less bytes and the implicit conversion is safe. We call it widening or promotion. In contrast, narrowing can be dangerous and cause a build warning.

# Build Process

• Preprocessing
• Compiling (where checks syntax and types)

In C++ we have two kinds of comments.

# References

In C++, people usually pass variables into functions by two methods: either by value or by reference. The first way creates a copy of the variable and nothing will happen to the original one. For the second, anything we do in the function will take effect on the original variable itself. The original variable must be declared once we create a reference, so

will compile, while below will not:

References can be extremely useful, especially when the original variable is a large object and making a copy costs considerable time and memory. However, this is potentially risky when we don't want to mess up with the original object when calling a function. So we need const references.

# Const References

There're two situations we should take care when using the const keyword with references. First, we can make a reference of a const variable, and we cannot change the value of it:

We may also bind a const reference to a variable when the original itself is not const:

In this case we avoid making a copy while also keep the original variable safe from unexpected editing.

# Pointers

There is a third way of passing a variable, that is pointers. Pointers are variables the points to their addresses in memory. We declare a pointer by

which comes with two unique operators: & for the address of a variable, and $*$ for the dereference of a pointer.

123

# New and Delete

You can create a pointer pointing to a piece of dynamic memory for later deletion, in case memory is being an issue in your program.

# Const Pointers

You can have pointers to a const variable, i.e. you cannot change its value through pointers.

You can also have const pointers to variables, then you can change the value of the variable but never again the pointer (address) itself.

You can also have const pointers to const variables.

# If/Else

Below is a general template for if/else structures in C++.

# Switch

When there're multiple conditions, we can also use the switch keyword.

# While

One of the most popular loops is while loop.

It also has a variant called the do/while loop.

which is slightly different from the while loop in sequence.

# For

Another form of loop that keeps track of the iterator precisely.

There is an unwritten rule that we usually write ++i in statement1 because compared with i++ which need to make a copy, ++i is more efficient. However, it's arguably correct because modern compilers can surely optimize this defect.

# Classes

A simple but intuitive example of classes is to describe a people in C++ (here we assume type string under the namespace std is used):

We can also implement member functions in the class, just to make it more convenient:

# Protection

We have three levels of data protection in a class:

• public: anyone have access
• private: only members can access
• protected: disccuss later

This means we can protect data in the class by declaring them as private while get access to them via public member functions:

# Constructor & Destructor

An instance created based on a class is called an object. To create an object, we may need a constructor, a copy constructor and a destructor.

# Coding Style

• We write each class definition in a separate header file
• We implement each class in a separate cpp file
• First letter of the class name is uppercase, e.g. Person
• Public member functions start with a upper case letter, private members use lower case
• Member variable names end with underscore, e.g. name_.

According to this coding style we have in Person.h

In Person.cpp we implement the member functions of the class:

Just keep in mind that the constructors as well as the destructor should also be implemented:

We can also use the colon syntax for constructors:

# Struct

a struct is a class with one difference: struct members are by default public, while class members are by default private.

For a newly created class we cannot use person2 = person1 if we want to assign the whole object person1 to person2. We have to use constructors. What we can do, instead, is to overload these operators (e.g. the assignment operator =) specifically for the class.

The overloadable operators include + - * / % ^ & | ~ ! = < > <= >= ++ -- << >> == != && || += -= *= /= &= |= ^= %= <<= >>= [] () -> ->* new new[] delete delete[].

The non-overloadable operators are :: .* . ?=.

However, such overloading does not support chain assignment like person3 = person2 = person1. We need to return a reference in order to support that.

where this is a pointer pointing to the object itself.

Another concern is self-assignment, which in some cases can be dangerous and in almost every situation is inefficient. To avoid self-assignment we need to detect and skip it.

# Include Guards

In C++, a function can only be defined once. This is called the One Definition Rule (ODR). To avoid multiple including of the header files, we use include guards. This is being done by defining a macro at the beginning of each header file.

# Containers

Here we introduce two of the most useful containers in the C++ Standard Library: std::vector and std::map. To initialize an empty vector, we use

and to initialize with a specific size, we do

On the other hand, map containers are like dict in Python, which allows you to use indiced of any type, e.g. std::string.

# Data Abstraction

Data abstraction refers to the separation of interface (public functions of the class) and implementation:

• A user of a class does not need to know how a member function in that class is implemented
• The interface shows you how to use it

# Encapsulation

Encapsulation refers to combining data and functions inside a class so that data is only accessed through the functions in the class.

# Friend

We can declare friend a function or class s.t. they can get access to the private and protected members of the base class.

and you can implement and use this function change_data globally in the function to change my_data.

# Inheritance

Inheritance refers to based on the existing classes trying to:

• Reuse code
• Improve maintainability and extensibility

A simple example would be

with meanwhile

Apparently a lot of functions and data are repeated. What we're gonna do is to build a base class and reuse it onto two derived classes. Note:

• A derived class inherits all members from the base class.
• A derived class may define additional members (data and/or function).

In actual coding, this is what we do:

with

and

To initialize a base class, we define constructors just like what we did before:

while for derived classes, we need to call the base class constructor

A derived class can access members in the base class, subject to protection level restrictions. Protection levels public and private have their regular meanings in an inheritance class hierarchy: 􏰀 - A derived class cannot access private members of a base class. - A derived class can access public members of a base class.

A derived class can also access protected members of a base class. If a class has protected members: 􏰀 - That class can access them - A derived class of that class can access them - Everone else cannot access them

# Virtual

A base class uses the virtual keyword to allow a derived class to override (provide a different implementation) a member function. If a function is virtual (in the base class): 􏰀 - The base class provides an implementation for that function; we call it the default implementation 􏰀- A derived classes inherit the function interface (definition) as well as the default implementation 􏰀- A derived class can provide a different implementation for that function (but it does not have to)

and then functions like Fun1 will be revisable in inheritance. Note that the base class has to implement all functions no matter they're virtual or not.

# Pure Virtual & Abstract Classes

If we don't give a default implementation of a virtual function, we call it pure virtual. This is been done by assigning =0 at the time of definition.

In this case the base class does not need to implement this Fun1 and in contrast, the derived class must do so. A class with virtual functions is called an abstract class. Note that we cannot instantiate (make an object of) an abstract class until every virtual function is implemented.

# Comparing Virtual & Pure Virtual

There's a slight difference between normal member functions, virutal functions and pure virtual functions during inheritance.

• For a normal member function, you don't necessarily need to implement it, but any derived class cannot change it
• For a virtual function, you can implement or not, and a derived class can redefine it
• For a pure virtual function, you must not implement it, and implementation is a must for any derived classes if you want to instantiate it

# Polymorphism

We use a pointer or a reference to a base class object to point to an object of a derived class, which we call the Liskov Substitution Principle (LSP).

More direct example may be as follows. Instead of writing separately

we can use polymorphism and write it w.r.t. the base class Option using a reference or pointer

# Const Member Functions

For variables we declare constancy by

For constant objects, e.g.

when we call

we meed a compile error. This is due to that the compiler does not know the function GetName is constant. To declare that we need

When we have pure virtual constant member functions, we write like this: virtual type f(...) const = 0.

# Mutable

A const member function cannot modify data members. The only exception of this issue is mutable data members.

# Override

The override keyword serves two purposes:

• It shows the reader of the code that "this is a virtual method, that is overriding a virtual method of the base class."
• The compiler also knows that it's an override, so it can "check" that you are not altering/adding new methods that you think are overrides.

In implementation of the pure virtual function foo in derived class derived1, we're doing just as told by the base class. In derive2, with the override keyword we'll get an error for overwriting the original virtual function by changing types; while without this keyword we'll get at most just a warning.

# Static

For non-static member we change an instance's data and it's done. Nothing will happen to other instances of the same derived class. For a static member function/data the association is built and we can change one and for all.

# Function Objects

A regular function is generally

while a function object implementation is

and for the latter we can use its instances as objects, which still work as functions.

where AddOne() is an unnamed instance of the class AddOne.

# Lambda

In C++ we have inline function definition as

The [] is called the capture operator and it has rules as follows.

• [=] captures everything by value (read but no write access)
• [&] captures everything by reference (read and write access)
• [=,&x] captures everything but x by value, and for x by reference
• [&,x] captures everything but x by reference, and for x by value

# OOP: Reviews

• Classes and Objects
• Data Abstraction and Encapsulation
• Inheritance
• Polymorphism

Below we introduce some features in STL.

# Methods

Two of the most commenly seen methods are begin() and end()

# Functions

We have binary_search, for_each, find_if and sort.

# Structure

In the STL, algorithms are implemented as functions, and data types in containers.

# STL & Lambda

By combining STL algorithms with lambdas in C++ can be very efficient. We can use lambdas in a loop without defining a function beforehand.

We can also use it as a sorting criterion

# Templates

We can have templates of a function:

We can also have templates of a class:

# File I/O

Specifically, for the open modes we have

Mode Description
ios::app Append to the end
ios::ate Go to the end of file on opening
ios::binary Open in binary mode
ios::in Open file for reading only
ios::out Open file for writing only
ios::nocreate Fail if you have to create it
ios::noreplace Fail if you have to replace
ios::trunc Remove all content if the file exists

# References

• Chanaka Liyanaarachchi. "Computing for Finance I" (2018).