Skip to content

mhered/cpp_tutorial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

C++ Tutorial for Complete Beginners

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

Pros/Cons of C++ (lesson #1)

  • 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

01_hello_world (lessons #3-4)

Shopping list:

  • Install a compiler: gcc / g++is industry standard

    cfr: 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 (withg++ becausestd::cout won't be accessible to gcc):

$ g++ hello_cpp.cpp -o hello_cpp
  • Execute it:
$ ./hello_cpp
Hello World!

C++ in Visual Studio Code

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/code

Edit 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

02_outputting_text (lessons #5-6)

03_strings (lesson #7)

04_input (lesson #8)

05_variables (lessons #9-12)

  • 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_t for unicode are 4 bytes
  • const: constant , yields compiler error if I try to reassign it again
  • scope of variables are the brackets where they are declared

06_if_else (lessons #14-17)

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) {...}

07_loops (lessons #18-21)

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

08_arrays (lessons #22-25)

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;
    };

09_switch (lesson #26)

switch(int or char){
    case 1:
        // code block 1
        break;
    ...
    case N:
        // code block N
        break;      
    default:
        // default code
}

10_functions (lessons #27-30)

Notes:

  • #include precompiler instructions paste in the contents of other files
  • #ifndef -#define - #endif structure 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.cpp file, declare their prototypes in a utils.h file, include the header in a main.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",
                ...

cfr. https://stackoverflow.com/questions/47665886/vs-code-will-not-build-c-programs-with-multiple-ccp-source-files

11_classes (lessons #31-38, #54)

  • 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 separate private: section. Anything that does not have to be accessible to the end user should be private. Make end user interaction only via documented public: 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 const methods that should not change state variables of the class

12_pointers_and_references (lessons #39, #45, #46)

  • 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_4 is a "constant pointer to a double that is constant"

13_arithmetics (lesson #40)

  • careful with integer division
  • casting into different types
  • use brackets for more readable precedences

14_array_pointers (lessons #41-42)

  • 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 long and do not use as a pointer but as an offset!!

15_char_arrays (lessons #43-44)

  • null termination character added at the end. Need to consider when calculating length LEN = sizeof()-1!
  • two methods of reversing a string

16_more_classes (lessons #47-50)

  • copy constructor receives a reference to a const object, i.e. inside we can only call const methods 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
  • new allocates memory. Need to call delete explicitly, C++ will not call destructor at end of scope!
  • special syntax pt_object->member is 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 NULL pointer, 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 new you 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

17_arrays_and_functions (lesson #51)

  • 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

18_namespaces (lesson #52)

  • namespaces avoid conflicts between classes and global variables

19_inheritance (lesson #53, #55)

  • 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. Vehicle methods cannot read or modify private data Machine.id, for this you need to use the methods inherited from Machine e.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

20_twos_complement (lesson #56)

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!

21_static (lesson #57)

  • static makes one shared variable for all objects of the class
  • static methods 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

22_particle_explosion (lessons #58-75,78)

Intro to libraries

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.lib in windows, libXYZ.a in linux/Mac (although can also include calls to load dynamic libraries)

  • dynamic libraries: code the program finds at run time XYZ.dll in windows libXYZ.so in linux/mac XYZ.dylib in mac

SDL graphics library

https://www.libsdl.org/

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

$ 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

Wrapping SDL in a Screen class

  • Encapsulate setup and tear down of SDL into a class Screen
  • Create a background that shifts color gradually

Animating particles

  • create Particle and Swarm classes
  • 5000 particles bouncing around at random speeds and slowly shifting color

Circular explosion

Consistent speed

  • use a timestamp to make the speed of motion independent of the computer clocking speed

Color management (lessons #66 and #73)

  • 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

Blurring & tweaking

OO design considerations (lesson #78)

  • not a fan of upfront design, prefers iterative design: prototype then refactor
  • try to encapsulate code in reusable, self-contained classes
  1. write a demo SDL program following the documentation
  2. encapsulate it in a Screen class. Very reusable code to setup and tear down
  3. Event handling was put in the methodScreen::process_events() because it was very simple, but could have been potentially a separate class
  4. particle entities were clear candidates to create its ownParticle class
  5. the code to deal with the big group of particles in Swarm class: create, delete, visit all particles to update them. Nothing SDL specific, so it is also reusable.
  6. Swarm and Screen are independent from each other. Swarm::get_particles() returns an array of particles and Screen::set_pixel() accesses individual pixels. We have a lot of code in the particle_explosion.cpp, we could imagine a class that knows about Swarm and Screen and connects them, wouldn't be very reusable.
  7. Screen::box_blur() could also have been a separate class.

What next (lesson #77)

  • Exceptions
  • File handling
  • Standard Template Library (STL)

23_prefix_postfix (lesson #79)

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;

24_polymorfism (lesson #80)

  • you can always use a derived class where a superclass is expected
  • use keyword virtual when 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 virtual to 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

25_static_libraries (lesson #81)

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 namespace to avoid conflicts
  • avoid unnecessary includes in the .h file
  • avoid general using namespace std; statements in the .h file 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.o

To 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 output

The -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 class

To do

  • compiling static libraries with vs code
  • using makefile with vs code

About

Notes on C++ Udemy tutorial

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors