Docsity
Docsity

Prepara i tuoi esami
Prepara i tuoi esami

Studia grazie alle numerose risorse presenti su Docsity


Ottieni i punti per scaricare
Ottieni i punti per scaricare

Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium


Guide e consigli
Guide e consigli


C++ advanced programming, Dispense di Programmazione C

Documento scritto da me in inglese sul linguaggio C++. La dispensa spiega argomenti avanzati del linguaggio in maniera chiara e semplice per poterne utilizzare tutte le capacità. Si parte dalle classi fino alla programmazione a oggetti, ereditarietà, polimorfismo e STL. Ogni argomento è corredato di esercizi svolti per comprendere meglio gli argomenti. Questo documento è adatto per chiunque indipendentemente dall'università/corso voglia approfondire la programmazione C++ in maniera strutturata e completa.

Tipologia: Dispense

2024/2025

In vendita dal 13/12/2024

giulio_russo
giulio_russo 🇮🇹

4.8

(42)

111 documenti

1 / 104

Toggle sidebar

Questa pagina non è visibile nell’anteprima

Non perderti parti importanti!

bg1
📶
Advanced
C++
💻
programming
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34
pf35
pf36
pf37
pf38
pf39
pf3a
pf3b
pf3c
pf3d
pf3e
pf3f
pf40
pf41
pf42
pf43
pf44
pf45
pf46
pf47
pf48
pf49
pf4a
pf4b
pf4c
pf4d
pf4e
pf4f
pf50
pf51
pf52
pf53
pf54
pf55
pf56
pf57
pf58
pf59
pf5a
pf5b
pf5c
pf5d
pf5e
pf5f
pf60
pf61
pf62
pf63
pf64

Anteprima parziale del testo

Scarica C++ advanced programming e più Dispense in PDF di Programmazione C solo su Docsity!

Advanced

C++

programming

Index

  • Random numbers
  • Exercise
  • Function pointers
  • Exercise
  • Casting
  • Exercise
  • String
  • Exercise
  • Object Oriented Programming (OOP)
  • Static
  • This pointer
  • Const
  • Exercise
  • Inheritence
  • Exercise
  • Virtual
  • Abstract classes
  • Exercise
  • Operator overloading
  • Exercise
  • Undesired program flows
  • Exception
  • Exercise
  • File
  • Exercise
  • Templates
  • Exercise
  • Standard Template Library (STL)
  • Vectors
  • Exercise
  • List
  • Exercise
  • Map
  • Exercise
  • Algorithm library
  • Exercise
  • Thanks

Random library : Starting with C++11, the library provides a more powerful and flexible way to generate random numbers, offering better randomness quality and more control. Components of the Library are:

  • Random Number Engines: Generate random numbers (e.g. std::default_random_engine).
  • Distributions: Define how the numbers are distributed (e.g. std::uniform_int_distribution, std::uniform_real_distribution). We can benefit of several advantages using the library:
  • Better Randomness: The quality of random numbers is better compared to rand().
  • Flexible Distributions: Allows for more than just uniform random numbers (e.g. normal distribution).
  • Reproducibility: By controlling the seed, you can reproduce the same sequence of random numbers. Example: #include #include // For random number generation #include // For time() int main() { // Create a random number engine and seed it with the current time std::default_random_engine engine(time(0)); // Create a uniform integer distribution from 1 to 100 std::uniform_int_distribution distribution(1, 100); // Generate and print random numbers for (int i = 0; i < 5; ++i) { // Generate a random number in the specified range int randomNum = distribution(engine); std::cout << "Random number: " << randomNum << std::endl; } return 0; } std::default_random_engine engine(time(0)); initializes the random number engine with a seed (in this case, the current time). std::uniform_int_distribution distribution(1, 100); specifies that numbers should be generated between 1 and
  1. distribution(engine); produces a random number using the specified distribution.

Exercise

  • Number Guessing: #include #include // For rand() and srand() #include // For time() int main() { // Seed the random number generator with the current time srand(time( 0 )); // Generate a random number between 1 and 100 int randomNumber = rand() % 100 + 1 ; int guess; std::cout << "Welcome to the Number Guessing Game!" << std::endl; std::cout << "I have selected a number between 1 and 100." << std::endl; std::cout << "Try to guess it!" << std::endl; // Loop until the player guesses correctly while (true) { // Get the player's guess std::cout << "Enter your guess: "; std::cin >> guess; // Check if the guess is too high, too low, or correct if (guess > randomNumber) { std::cout << "Too high! Try again." << std::endl; } else if (guess < randomNumber) { std::cout << "Too low! Try again." << std::endl; } else { std::cout << "Congratulations! You guessed the number!" << std::endl; break; // Exit the loop when the guess is correct } } return 0 ; }

Function pointers

In C++, function pointers are pointers that point to the address of a function rather than a data variable. Using function pointers allows you to dynamically decide which function to call at runtime, which can be particularly useful in scenarios like passing functions as arguments to other functions.

Definition: Function pointers declare the function structure they are able to point: RETURN_TYPE (* FUNCTION_POINTER_NAME )( DATA_TYPE_PARAMETER1 , ...); Assignment: Once you declare a function pointer, you can assign it to any function that matches the same signature. FUNCTION_POINTER_NAME = FUNCTION_NAME ; Calling: Once a function pointer is set, you can use it to call the function it points to, similar to calling the function directly. Write the function call specifying all thenecessary arguments, using the function pointer name. Example: #include int add(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } int main() { int (*operation)(int, int); // Declare a function pointer int choice; std::cout << "Enter 1 to add, 2 to subtract: "; std::cin >> choice; if (choice == 1) { operation = add; // Point to add function } else if (choice == 2) { operation = subtract; // Point to subtract function } else { std::cout << "Invalid choice!" << std::endl; return 1; } int result = operation(10, 5); // Call the chosen function via pointer std::cout << "Result: " << result << std::endl; return 0; }

Exercise

  • Calculator: #include // Function declarations for arithmetic operations double add(double a, double b) { return a + b; } double subtract(double a, double b) { return a - b; } double multiply(double a, double b) { return a * b; } double divide(double a, double b) { if (b == 0 ) { std::cerr << "Error: Division by zero!" << std::endl; return 0 ; } return a / b; } int main() { double num1, num2; char operation; double (*operationFunc)(double, double); // Function pointer declaration std::cout << "Enter first number: "; std::cin >> num1; std::cout << "Enter an operator (+, -, , /): "; std::cin >> operation; std::cout << "Enter second number: "; std::cin >> num2; // Select the appropriate function based on the operator switch (operation) { case '+': operationFunc = add; break; case '-': operationFunc = subtract; break; case '': operationFunc = multiply; break; case '/': operationFunc = divide; break;

Casting

Type casting is the process of converting a variable from one data type to another. C++ provides both traditional (C-style) casting and modern (C++-style) casting, which offers more explicit and safer ways to handle type conversions. There are several types of casting in C++. Let's explore the two main one:

  • C-Style Casting: C-Style casting is the traditional form of type casting inherited from the C programming language. It uses a simple syntax and can perform multiple types of conversions, but it’s generally considered unsafe because it provides minimal control over what is being cast. ( DATA_TYPE ) VARIABLE_NAME or: DATA_TYPE ( VARIABLE_NAME ) Example: int a = 10; double b = (double) a; // Converts int to double While C-style casting is simple, it’s not recommended in modern C++ because it can be ambiguous and may hide potential errors, especially when dealing with complex data types or object-oriented code.
  • static_cast: static_cast is the most common and safest cast in C++. It is used for converting related types (e.g. int to double, float to int) and upcasting in inheritance hierarchies (e.g. converting a derived class pointer to a base class pointer). Converts between compatible types and performs compile-time checks, making it safer than C-style casts. static_cast< DATA_TYPE >( VARIABLE_NAME ) Example: int a = 42; double b = static_cast(a); // Converts int to double // Pointer upcasting class Base {}; class Derived : public Base {}; Derived d; Base* basePtr = static_cast<Base>(&d); // Upcast from Derived to Base*

Exercise

  • Temperature conversion: #include int main() { int fahrenheitTemp; // Prompt user to enter a temperature in Fahrenheit std::cout << "Enter temperature in Fahrenheit (integer): "; std::cin >> fahrenheitTemp; // C-style casting: Convert Fahrenheit (int) to Celsius (float) float celsiusTempCStyle = (float)(fahrenheitTemp - 32 ) * 5 / 9 ; std::cout << "C-style cast conversion to Celsius: " << celsiusTempCStyle << "°C" << std::endl; // static_cast: Convert Fahrenheit (int) to Celsius (float) float celsiusTempStaticCast = static_cast(fahrenheitTemp - 32 ) * 5 / 9 ; std::cout << "static_cast conversion to Celsius: " << celsiusTempStaticCast << "°C" << std::endl; // Convert Celsius back to Fahrenheit to check accuracy // C-style casting: Celsius to Fahrenheit int fahrenheitBackCStyle = (int)(celsiusTempCStyle * 9 / 5 + 32 ); std::cout << "C-style cast conversion back to Fahrenheit: " << fahrenheitBackCStyle << "°F" << std::endl; // static_cast: Celsius to Fahrenheit int fahrenheitBackStaticCast = static_cast(celsiusTempStaticCast * 9 / 5 + 32 ); std::cout << "static_cast conversion back to Fahrenheit: " << fahrenheitBackStaticCast << "°F" << std::endl; return 0 ; }

Comparing Strings : Strings can be compared using comparison operators (==, !=, <, >, etc.) or the compare() method: STRING1 .compare( STRING2 ) Example: std::string str1 = "apple"; std::string str2 = "banana"; if (str1 == str2) { std::cout << "Strings are equal." << std::endl; } else { std::cout << "Strings are not equal." << std::endl; } // Using compare() int result = str1.compare(str2); if (result == 0) { std::cout << "Strings are equal." << std::endl; } else if (result < 0) { std::cout << "str1 is less than str2." << std::endl; } else { std::cout << "str1 is greater than str2." << std::endl; } Substrings : The substr() method extracts a substring from the string: STRING .substr( START_INDEX , STOP_INDEX ) Example: std::string phrase = "Hello, World!"; std::string sub = phrase.substr(7, 5); // Starting at index 7, length 5 std::cout << sub << std::endl; // Outputs: World The find() method locates a substring within a string, returning the index of the first occurrence, or the standard value std::string::nposif if no match is found: STRING .find( SUBSTRING ) Example: std::string text = "Hello, World!"; std::size_t pos = text.find("World"); if (pos != std::string::npos) { std::cout << "'World' found at position: " << pos << std::endl; } else { std::cout << "'World' not found" << std::endl; }

Modifying strings : std::string provides several methods to modify strings:

  • push_back( CHARACTER ): Adds a character to the end of the string.
  • pop_back(): Removes the last character.
  • insert( POSITION , STRING ): Inserts a substring at a specified position.
  • erase( POSITION , LENGTH ): Erases part of the string from position for length characters. Example: std::string phrase = "Hello"; phrase.push_back('!'); // Adds '!' to the end phrase.insert(0, "Say "); // Inserts "Say " at the beginning phrase.erase(4, 1); // Erases 1 character at index 4 std::cout << phrase << std::endl; // Outputs: Say Hello! Size : std::string provides a convenient function to obtain the size of the string: STRING .size() Example: std::string word = "Hello"; std::cout << "Size: " << word.size() << std::endl;

Converting Between std::string and C-Style Strings : To get a C-style string from an std::string, use the c_str() method: CPP_STRING .c_str(); Example: std::string cppString = "Hello"; const char* cString = cppString.c_str(); std::cout << cString << std::endl; // Outputs: Hello Conversely, you can initialize an std::string with a C-style string: std::string CPP_STRING ( C_STRING ); Example: const char* cStr = "World"; std::string cppStr(cStr); std::cout << cppStr << std::endl; // Outputs: World

Object Oriented Programming (OOP)

Object-Oriented Programming (OOP) is a programming paradigm that organizes code based on objects rather than actions. It models real-world entities as software objects, each encapsulating data (attributes) and behavior (methods). OOP is designed to increase code modularity, reusability, and scalability, making it easier to build complex and maintainable software. Define:

  • Class: A blueprint for creating objects, defining data members (attributes) and member functions (methods).
  • Object: An instance of a class that holds actual data.

Define class : The two main content of a class are:

  • Attributes: variables that hold data related to the object.
  • Methods: functions that perform actions related to the object and can access its data members. Its definition follow the same rules of a normal function. This is a big step compared to the Struct: Struct group only variables, Classes group variables and methods. Also their access can be managed with different specifiers. Class structure can be written on top outside of the main(). The general syntax is: class CLASS_NAME { ACCESS_SPECIFIER : // Attributes DATA_TYPE ATTRIBUTE_NAME1 ; DATA_TYPE ATTRIBUTE_NAME2 ; ... // Methods RETURN_TYPE FUNCTION_NAME ( DATA_TYPE PARAMETER_NAME1 , ...) { // Code for public method } ... }; Example (let's consider for now a specifier "public", we will get to that later): class Car { public: int number; void displayNumber() { std::cout << "The car number is: " << number << std::endl; } }; Note that there is no need to pass the class attributes into the function. This happen because the class attributes are already available for the class methods. Car: number displayNumber()

Create Object : Once the blueprint of the class is defined, we have to be able to create variables of the type of the class: an object. Each object has its own set of attributes (as it was for the Struct) and methods. CLASS_NAME OBJECT_VARIABLE_NAME ; Example: Car myCar; Access attributes and methods : Attributes and methods can be accessed with the dot notation, as it was done for the Struct.

  • Access attributes: write the name of the object vairable and after the dot specify the attribute name. OBJECT_VARIABLE_NAME. ATTRIBUTE_NAME1 ;
  • Access methods: write the name of the object variable and after the dot specify the method name and its parameters. Calling a method is the same of calling a function. OBJECT_VARIABLE_NAME. FUNCTION_NAME (...); Example: // Modify the object attribute myCar.number = 42; // Call the object method myCar.displayNumber(); Constructors, Copy Constructors and Deconstructors : In C++, classes can constructors and destructors are special member functions of a class that help manage the initialization and cleanup of objects.
  • Constructor: is a special function that is called automatically when an object of a class is created. Its main purpose is to initialize the attributes of the class. The method has this structure: CLASS_NAME ( DATA_TYPE PASSED_ATTRIBUTE_NAME1 , ...) { ATTRIBUTE_NAME1 = PASSED_ATTRIBUTE_NAME1 ; ... } Let's see more in details what happen: myCar: number displayNumber() myCar: number: 42 displayNumber()
  • Copy constructor: "explain" how to create a copy of an object in case it is needed, like when an object is passed by value to a function or you create a new object from an existing object (e.g. Car newCar = myCar). This function answer the question: "What is the meaning of copying an object?" and "What has to be done in order to copy an object?" If you don't define a copy constructor, the compiler provides a default copy constructor that performs a shallow copy (copies all members as-is). But you may need to create a custom copy constructor, for example if your class deals with dynamic memory allocation or needs to perform a deep copy. CLASS_NAME (const CLASS_NAME & OBJECT_VARIABLE_NAME ) { ATTRIBUTE_NAME1 = OBJECT_VARIABLE_NAME.ATTRIBUTE_NAME1 ; ... } Example: class Car { public: int max_speed; int number; // Constructor Car(int n, int ms) { number = n; max_speed = ms; } // Copy Constructor Car(const Car& other) { number = other.number number of myCar: 123 max_speed = other.max_speed speed of myCar: 1000 } void displayNumber() { std::cout << "The car number is: " << number << std::endl; } }; If we create an object and we want to create a copy of it, the copy constructor is called: Car myCar(123, 1000); Car newCar = myCar; number max_speed The attributes of the passed objects (the one on the right side of the equal sign) are the one copied inside the attributes of the calling object (the one on the left side of the equal sign)
  • Deconstructor: is a special function that is called automatically when an object goes out of scope or is explicitly deleted. Its main purpose is to release resources (e.g. memory) that were allocated during the object's lifetime. ~ CLASS_NAME () { ... } Example: class DynamicArray { public: int* arr; // Pointer to dynamically allocated array int size; // Constructor to allocate memory DynamicArray(int s) { size = s; arr = new int[size]; // Allocate memory on the heap for (int i = 0; i < size; ++i) { arr[i] = i + 1; // Initialize array elements } std::cout << "Constructor: Array of size " << size << " created."; } // Destructor to deallocate memory ~DynamicArray() { delete[] arr; // Deallocate memory to prevent memory leak std::cout << "Destructor: Array of size " << size << " deleted."; } }; Access specifiers : In C++, access specifiers define the visibility and accessibility of members (data and methods) in a class. They control how data members and member functions of a class can be accessed from outside. The three main access specifiers in C++ are
  • public: accessible from anywhere in the program, typically used for parts of the class that need to be accessible to other parts of the program without restrictions. class Car { public: int year; // Public attribute // Public method void displayInfo() { std::cout << "Year: " << year << std::endl; } }; ... Car myCar; myCar.brand = "Toyota"; // Accessible from outside the class myCar.year = 2022; // Accessible from outside the class myCar.displayInfo(); // Accessible from outside the class