Udemy Free Tutorial: https://www.udemy.com/course/free-learn-c-tutorial-beginners/
Repo: https://github.com/caveofprogramming/cplusplus-beginners
W3 C++ reference: https://www.w3schools.com/cpp/default.asp
-
Challenging to learn
-
Often time-consuming to write
-
Low level:
-
Powerful: Very fast execution / Allows to access hardware. Good for real time, device drivers
-
Does not protect you from yourself -> Easy to introduce terrible bugs
-
Issues instructions directly to the computer, i.e. no virtual machine: Not truly platform-independent
-
Shopping list:
-
Install a compiler:
gcc/g++is industry standardcfr: https://linuxize.com/post/how-to-install-gcc-on-ubuntu-20-04/?utm_content=cmp-true
Normally already available as part of Ubuntu 20.04 distro, check with:
$ g++ --version g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
Create a file
hello_cpp.cpp// hello_cpp.cpp #include <iostream> using namespace std; int main() { cout << "Hello World!" << endl; return 0; }
-
Compile it (with
g++becausestd::coutwon't be accessible togcc):
$ g++ hello_cpp.cpp -o hello_cpp- Execute it:
$ ./hello_cpp
Hello World!Install and configure an IDE: he uses Eclipse CDT, I will use Visual Studio Code
Refer to:
Modify tasks.json to change the behavior of the build, e.g. to place compiled binaries in a bin/ subfolder, i.e.:
$ g++ -g code.cpp -o ./bin/codeEdit tasks.json as follows:
...
"tasks": [
{
...
"args": [
"-g",
"${file}",
"-o",
"${fileDirname}/bin/${fileBasenameNoExtension}"
],
...
F5: build and debug
F9: toggle breakpoint
CTRL+SHIFT + i: autoformat
CTRL+SHIFT + p: command window
-
C++ section of the VS Code website, with topics on:
- Integer types:
int,short,long,unsigned: There are limits to the values that can be stored in different types, cfr: https://www.tutorialspoint.com/c_standard_library/limits_h.htm Overflowing values don't automatically raise error messages! - Floating types:
float,double,long double bool: true(1) or false(0)char: 1 byte,wchar_tfor unicode are 4 bytesconst: constant , yields compiler error if I try to reassign it again- scope of variables are the brackets where they are declared
if(condition1){
// code block 1
} else if(condition2){
// code block 2
} else {
// final code block
} Logical operators: && and, || or, ! not
Multiple conditionals evaluate left to right but for better readability (1) use parentheses and (2) store partial conditions in bool variables. E.g. instead of:
if (value2 !=8 && value1 == 10 || value1<10) {...}It is better:
bool condition1 = (value2 !=8) && (value1 == 10);
bool condition2 = value1 < 10;
if (condition1 || condition2) {...}while(){}: loop executes while condition is true
while(condition){
// code block 1
}do{}while(): always executes code block at least once
do{
// code block 1
} while(condition)for(){} loop:
- initialization statement: executed once, before the execution of the code block. Used to init counter. Note exceptionally the counter will be available inside the code block.
- exit condition: code block executes while this condition is true, exits when false.
- update statement: executed (every time) after the code block.
for (initialization statement; exit condition; update statement;) {
// code block
}continue: skip to next iteration
break: stop iteration
Notes:
- if not initialized there will be garbage
- nothing prevents you from accesing an index out of the array and this yields garbage!
- string object stores a pointer, fixed size 8 bytes
- use loops to initialize and process
- use sizeof to make size independent
Example of 2D array below:
// multidimensional array, sizeof
string animals[2][3] = {
{"fox", "dog", "mouse"},
{"cat", "squirrel", "parrot"}};
int rows = sizeof(animals)/sizeof(animals[0]);
int cols = sizeof(animals[0])/sizeof(string); // sizeof(string) = 8, its a pointer!
cout << rows << " x " << cols <<endl;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
cout << animals[i][j] << " " << flush;
}
cout << endl;
};switch(int or char){
case 1:
// code block 1
break;
...
case N:
// code block N
break;
default:
// default code
}Notes:
#includeprecompiler instructions paste in the contents of other files#ifndef -#define - #endifstructure prevents duplicated inclusion- header files contain function prototypes so it is not needed to declare functions before calling them
- C++ is typed: need to declare types of function arguments
- typical structure: define functions in a
utils.cppfile, declare their prototypes in autils.hfile, include the header in amain.cppfile to make the functions available - In VS code, to build all cpp files in a folder modify the following line in
tasks.json:
"args": [
...
"-g",
"${fileDirname}/**.cpp",
...- creating classes is analogous to creating your own variable types
- classes bundle methods and data representing state
- encapsulation: make as much of the class private as possible: define as many variables as possible in
private:and typically put private methods in a separateprivate:section. Anything that does not have to be accessible to the end user should be private. Make end user interaction only via documentedpublic:methods, e.g. setter and getter methods to manipulate private variables (which are actually not recommended) - constructor is the place to initialize instance variables
- destructor runs when instance is destroyed (natural scope ends in next closing curly bracket
}) - overloading methods: defining methods with the same name and different parameters (cannot differ only in return type). Typical with constructors, but not exclusive
- short methods can be implemented inline in the Class definition
- in constructor and setters use the same names for parameters as for the corresponding instance variables and use the
this->pointer to distinguish them - in constructors it is recommended instead (and faster) to use initialization lists to initialize the variables, either in the header if short or in the .cpp if longer. It is possible to pass parameters or to initialize with fixed values. You can also initialize some parameters in the initialization list and others inside the curly brackets
{}as needed. - Good practice to declare as
constmethods that should not change state variables of the class
- functions that take pointers can receive &var as parameter and make persistent changes
// example function takes pointer as parameter and modifies its content
void manipulate(int* pointer) {*pointer*=2}
int var;
manipulate(&var) // if called with &var, it makes persistent changes in var&has two uses: 'address of' and 'reference to' (to make an alias). How to distinguish?
double var1 =1.0;
double *pointer = &var1; //create a pointer to the address of an existing variable
double &var2 = var1; // create an alias (instead of a copy) of var1- two ways to modify a pointer: modify memory location where it points or modify what is stored in the memory location read from right to left:
const double *const pt_4is a "constant pointer to a double that is constant"
- careful with integer division
- casting into different types
- use brackets for more readable precedences
- loop trough array using array elements syntax, with for loop incrementing pointers or in a while loop comparing pointers to break
- careful when subtracting pointers: cast the result to
longand do not use as a pointer but as an offset!!
- null termination character added at the end. Need to consider when calculating length
LEN = sizeof()-1! - two methods of reversing a string
- copy constructor receives a reference to a
constobject, i.e. inside we can only callconstmethods of the object being copied (we do not want to modify the original!) - if we don't define it explicitly C++ makes an implicit copy constructor and does not call the normal constructor
newallocates memory. Need to calldeleteexplicitly, C++ will not call destructor at end of scope!- special syntax
pt_object->memberis equivalent to(*pt_object).member - typical source of bugs, e.g. not deleting object pointers causing memory leaks, deleting a pointer not created with new, deleting a
NULLpointer, etc. - two types of memory: stack and heap. Stack is a small LIFO, keeps addresses of functions and local variables. stack overflow if you call function iteratively. With
newyou allocate memory in the heap which is larger. - we can use new and [] to allocate memory for an array of objects without instantiating them. Remember to delete all after using them. Works also with primitive types.
Animal *pt_animal = new Animal()[10];
...
delete [] pt_animal; //no need to specify the size- C++ does not pass an array to/from functions, just a pointer to the first element and the array size information is lost.
- when passing an array to a function need to pass the size information, except with really ugly syntax
void show3(string (&texts)[3])that also forces to know in advance the size - when a function returns an array you need to explicitly return the size
- namespaces avoid conflicts between classes and global variables
- inheritance allows to create a child or subclasses from another superclass adding or modifying some functionality. subclasses are types of the superclass
- constructors are not inherited, instead both constructors of the superclass and the subclass are called in sequence (superclass first)
- from the subclass we cannot access the private data of the superclass (e.g.
Vehiclemethods cannot read or modify private dataMachine.id, for this you need to use the methods inherited fromMachinee.g. the constructor, orMachine.info()which is public) - to initialize a subclass we can specify which constructor from the direct superclass to run and pass it the parameters in the initialization list
max unsigned value stored in N-bit system is 2^N -1
max signed value is 2^(N-1) -1
min signed value is 2^(N-1)
Two's complement is the system used to store values
Most significant bit used for sign (1 means negative)
we discard overflow
Example with 3-bit:
000: 0
001: 1
010: 2
011: 3
100: -4
101: -3
110: -2
111: -1
0010 (2) +
0110 (-2) =
1000 -> discard overflow -> 000 (0) OK!
staticmakes one shared variable for all objects of the classstaticmethods can only access static variables (no guarantee that any objects have actually been created)- Classic uses:
- define class constants: typically public, named in capitals and initialized in the .h file
- create a counter of objects created
preprocessor
compilation from source (.cpp) to object file (.o)
link (in XYZ.exe or no suffix ) links also to libraries
-
static libraries: files with actual c++ code that is compiled into your program.
XYZ.libin windows,libXYZ.ain linux/Mac (although can also include calls to load dynamic libraries) -
dynamic libraries: code the program finds at run time
XYZ.dllin windowslibXYZ.soin linux/macXYZ.dylibin mac
we need header files, static libraries to link with and a dynamic library the static refers to and that you need to distribute as well
- Installation is one line as per instructions in http://wiki.libsdl.org/SDL2/Installation complemented with https://www.geeksforgeeks.org/sdl-library-in-c-c-with-examples/ (to add SDL_image). Note I had to remove
libsdl2-dbgandlibsdl2-image-dbg
$ sudo apt-get install libsdl2-2.0-0 libsdl2-dev libsdl2-image-2.0-0 libsdl2-image-dev
$ ls /usr/include/SDL2
begin_code.h SDL_log.h SDL_stdinc.h
close_code.h SDL_main.h SDL_surface.h
SDL_assert.h SDL_messagebox.h SDL_system.h
SDL_atomic.h SDL_mouse.h SDL_syswm.h
SDL_audio.h SDL_mutex.h SDL_test_assert.h
SDL_bits.h SDL_name.h SDL_test_common.h
SDL_blendmode.h SDL_opengles2_gl2ext.h SDL_test_compare.h
SDL_clipboard.h SDL_opengles2_gl2.h SDL_test_crc32.h
SDL_config.h SDL_opengles2_gl2platform.h SDL_test_font.h
SDL_cpuinfo.h SDL_opengles2.h SDL_test_fuzzer.h
SDL_egl.h SDL_opengles2_khrplatform.h SDL_test.h
SDL_endian.h SDL_opengles.h SDL_test_harness.h
SDL_error.h SDL_opengl_glext.h SDL_test_images.h
SDL_events.h SDL_opengl.h SDL_test_log.h
SDL_filesystem.h SDL_pixels.h SDL_test_md5.h
SDL_gamecontroller.h SDL_platform.h SDL_test_memory.h
SDL_gesture.h SDL_power.h SDL_test_random.h
SDL.h SDL_quit.h SDL_thread.h
SDL_haptic.h SDL_rect.h SDL_timer.h
SDL_hints.h SDL_render.h SDL_touch.h
SDL_image.h SDL_revision.h SDL_types.h
SDL_joystick.h SDL_rwops.h SDL_version.h
SDL_keyboard.h SDL_scancode.h SDL_video.h
SDL_keycode.h SDL_sensor.h SDL_vulkan.h
SDL_loadso.h SDL_shape.h
$ ls -a /usr/lib/x86_64-linux-gnu/libSDL*
/usr/lib/x86_64-linux-gnu/libSDL2-2.0.so
/usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0
/usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.10.0
/usr/lib/x86_64-linux-gnu/libSDL2.a
/usr/lib/x86_64-linux-gnu/libSDL2_image-2.0.so
/usr/lib/x86_64-linux-gnu/libSDL2_image-2.0.so.0
/usr/lib/x86_64-linux-gnu/libSDL2_image-2.0.so.0.2.3
/usr/lib/x86_64-linux-gnu/libSDL2_image.a
/usr/lib/x86_64-linux-gnu/libSDL2_image.so
/usr/lib/x86_64-linux-gnu/libSDL2main.a
/usr/lib/x86_64-linux-gnu/libSDL2.so
/usr/lib/x86_64-linux-gnu/libSDL2_test.a-
For configuration of VS code to compile SDL2: added
,"-lSDL2", "-lSDL2_image"toargsintasks.jsonand,"/usr/include/SDL2"toincludePathinc_cpp_properties.jsonas seen here: https://stackoverflow.com/questions/69019675/visual-studio-code-with-sdl-library-cant-build-undefined-reference-problem and here: https://stackoverflow.com/questions/32468761/how-can-i-link-with-gcc-and-sdl-image-library -
Demo examples
sdl_demo.cppandsdl_demo_ducky.cppadapted from here: https://www.geeksforgeeks.org/sdl-library-in-c-c-with-examples/
- Encapsulate setup and tear down of SDL into a class
Screen - Create a background that shifts color gradually
- create
ParticleandSwarmclasses - 5000 particles bouncing around at random speeds and slowly shifting color
- use a timestamp to make the speed of motion independent of the computer clocking speed
- Use bit shifting to compose a RGB hex from 3 color components (cfr.
Screen::set_pixel()):
// 0x99e6ff DeepSkyBlue 80%
unsigned char red = 0x99;
unsigned char green = 0xe6;
unsigned char blue = 0xff;
int rgb = 0;
rgb += red; // 0x000099
rgb <<= 8; // 0x009900
rgb += green; // 0x0099e6
rgb <<= 8; // 0x99e600
rgb += blue; // 0x99e6ff- Use bitwise and
&to apply a mask and bit shifting to decompose a RGB hex into the 3 color components:
unsigned char red = (rgb & 0xFF0000) << 16; // & to apply mask then bit shifting
unsigned char green = (rgb & 0x00FF00) << 8; // & to apply mask then bit shifting
unsigned char blue = (rgb & 0x0000FF); // & to apply mask- not a fan of upfront design, prefers iterative design: prototype then refactor
- try to encapsulate code in reusable, self-contained classes
- write a demo SDL program following the documentation
- encapsulate it in a
Screenclass. Very reusable code to setup and tear down - Event handling was put in the method
Screen::process_events()because it was very simple, but could have been potentially a separate class - particle entities were clear candidates to create its own
Particleclass - the code to deal with the big group of particles in
Swarmclass: create, delete, visit all particles to update them. Nothing SDL specific, so it is also reusable. SwarmandScreenare independent from each other.Swarm::get_particles()returns an array of particles andScreen::set_pixel()accesses individual pixels. We have a lot of code in theparticle_explosion.cpp, we could imagine a class that knows aboutSwarmandScreenand connects them, wouldn't be very reusable.Screen::box_blur()could also have been a separate class.
- Exceptions
- File handling
- Standard Template Library (STL)
int value1 = 8;
int value2 = value1++; // postfix: value2 is assigned before value1 incremented: value2 = 8, value1 = 9
cout << "Value1 is: " << value1 << endl;
cout << "Value2 is: " << value2 << endl;
int value3 = ++value1; // prefix: value3 assigned after value1 incremented: value3 = value1 = 10
cout << "Value1 is: " << value1 << endl;
cout << "Value3 is: " << value3 << endl;- you can always use a derived class where a superclass is expected
- use keyword
virtualwhen you anticipate to create subclasses with overridden methods -> when you override methods c++ creates a "v table" to call the appropriate method depending on the subclass created - only needed in the base class, but good practice to add virtual in all intermediate subclasses
- usually destructors should always be
virtualto ensure the proper memory cleanup. - useful e.g. to make an array of objects of different subclasses call a base method and each object will run their overridden version of the method
Libraries allow reusing classes or code. Two types:
- dynamic libraries (
.dll,.so) are shared among programs and loaded at run time. Live in the same folder as the main or in a special folder in the system. - static libraries: built into your executable.
Creating libraries with gcc: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/GCC/create-libraries/index
Recommendations:
- use
namespaceto avoid conflicts - avoid unnecessary includes in the
.hfile - avoid general
using namespace std;statements in the.hfile to avoid conflicts
Compile with -c to create objects instead of executables, then create a static library with the ar tool ( r means to insert with replacement, c means to create a new archive, and s means to write an index):
$ gcc -c my_library1.cpp -o my_library1.o
$ gcc -c my_library2.cpp -o my_library2.o
$ ar rcs libmy_library.a my_library1.o my_library2.oTo compile the program into a standalone executable output (Note: with gcc it does not find iostream):
$ g++ main.o -Lpath-to-libs -lmy_library -o outputThe -L flag indicates (a non standard) directory where the libraries can be found.
The -l flag indicates the name of the library. Note, that it assumes the library to start with lib and end with .a (so lib and .a must not be specified)
In our case:
$ cd my_library
$ gcc -c TestClass.cpp -o TestClass.o
$ gcc -c testfunctions.cpp -o testfunctions.o
$ ar rcs libteststaticlibrary.a TestClass.o testfunctions.o
$ cp libteststaticlibrary.a TestClass.h testfunctions.h ../lib/
$ cd ..
$ g++ program_using_library.cpp -Llib -lteststaticlibrary -o bin/program_using_library
$ ./bin/program_using_library
Message from test function
Message from test classTo do
- compiling static libraries with vs code
- using makefile with vs code



