Upgrade to Pro — share decks privately, control downloads, hide ads and more …

C / C++ - language

C / C++ - language

Jussi Pohjolainen

June 10, 2024
Tweet

More Decks by Jussi Pohjolainen

Other Decks in Technology

Transcript

  1. C: Mother of all Languages • Many programming languages are

    directly derived from C or are heavily influenced by its syntax and design • C++: • Built on C with object-oriented features. • Objective-C: • A C-based language with object-oriented extensions. • Java and C#: • Adopted C-like syntax and many concepts. • JavaScript, Go, Rust, Swift, PHP, ... • Designed in the 70s! • 1978: Kernighan + Ritchie: "The C Programming Language" • From 1989 -> 2018 ANSI C standard. • 2018: C18 (ISO/IEC 9899:2018) language standard • Free doc: https://en.cppreference.com/w/c
  2. Use Cases? • Operating Systems: • C is frequently used

    to develop operating systems due to its low-level capabilities and direct access to system hardware. Examples include UNIX, Linux, Windows, and macOS kernels. • Embedded Systems: • C's ability to directly interact with hardware makes it ideal for programming microcontrollers and embedded systems found in appliances, automotive systems, and consumer electronics. • Compilers and Interpreters: • Many compilers and interpreters for other programming languages are themselves written in C due to its performance and ability to manipulate system resources effectively. • Game Development, Networking, IoT Devices, Libraries...
  3. Machine Code • Definition: The lowest-level programming language, consisting of

    binary code (0s and 1s) that the CPU directly executes. • Human Readability: Not human-readable; it's difficult to interpret and write directly. • Portability: Not portable across different types of CPUs, as different CPUs have different instruction sets. • Usage: Used for critical performance-sensitive applications, but typically generated automatically by compilers.
  4. Assembly Code • Definition: A low-level programming language that provides

    a symbolic representation of machine code instructions. • Human Readability: Slightly human-readable with mnemonics for operations (e.g., MOV, ADD) and labels for memory addresses. • Portability: Hardware-specific and not portable across different CPU architectures. • Usage: Used for system programming, device drivers, and performance-critical code where hardware control is necessary. • First C – compiler was written with assembly
  5. An instruction set • An instruction set architecture (ISA), is

    a set of commands that a particular processor (CPU) can execute • These instructions are low-level commands that tell the CPU to perform basic operations • add, subtract, .. • AND, OR, XOR • Data movement • Control Flow • Input / Output • Assembly code is basically using these instruction sets • x86, ARM, MIPS, PowerPC
  6. Compiling • Assembly code is compiled into machine code using

    a tool called assembler • NASM (Linux + Windows) • MASM (Microsoft Macro Assembler) • FASM (Flast Assembler) • Translates the assembly instructions into binary machine code that CPU can execute
  7. C - language • High – level language • More

    focus on programming logic than detailed knowledge of hardware • Portability: same code can be compiled to different architectures • Readability • Maintainability
  8. // Preprocessor directive to include the standard input-output header file.

    // This file contains declarations for the I/O functions like printf and scanf. #include <stdio.h> // The main function where program execution begins. // It returns an integer value to the operating system. int main() { // The printf function is used to print the string "Hello, World!" to the console. // The \n is a newline character, which moves the cursor to the next line after printing the string. printf("Hello, World!\n"); // The return statement ends the main function and returns the value 0 to the operating system. // Returning 0 typically indicates that the program finished successfully. return 0; }
  9. GCC Compiler • GCC (GNU Compiler Collection) is a compiler

    system developed by the GNU Project • C, C++, Objective-C, Fortran, Ada, and others • Open source and free
  10. Installing • macOS • Install Xcode command line tools •

    Linux (Debian/Ubuntu) • sudo apt update && sudo apt install gcc • Windows • https://winlibs.com/
  11. WinLibs • Win32 vs. Win64: • Choose based on whether

    you need a 32-bit or 64-bit toolchain. • 64-bit is generally preferred for modern development due to better performance and the ability to handle larger memory. • Posix vs MCF • POSIX Threads • Standard threading model used in Unix-like systems. Code is portable across systems. Widely Supported. #include <pthread.h> • MCF Threads • Not standardized, less portable, designed for massive concurrency, efficiently handling very large number of threads.
  12. Basic Types • int (32 bits, 4 bytes)* • Stores

    integers (whole numbers), both positive and negative. • float (32 bits, 4 bytes)* • Stores single precision floating point numbers (numbers with a fractional part). • double (64 bits, 8 bytes)* • Stores double precision floating point numbers, providing more precision than float. • char (8 bits, 1 byte)* • Stores individual characters or small integers (usually 1 byte). • * Usually, can vary depending on OS and compiler
  13. Bits, Byte? bit: 0 or 1 byte (8 bits): 01011010

    // Example, character 'a' byte (8 bits): 01100001 => integer 97 => 'a'
  14. Basic Types int age = 30; // An integer variable

    int temperature = -5; // Can store negative values float weight = 65.5; // A floating-point number float height = 175.0f; // Suffix 'f' denotes a float literal double distance = 123.456; // A double precision floating point number char initial = 'A'; // Stores a single character char escape = '\n'; // Escape character for new line
  15. Modifier types • signed • Allows storage of both positive

    and negative numbers. • unsigned • Only allows positive values and zero, effectively doubling the maximum value of a data type. • short • Used with int to specify a shorter integer. • long • Used with int to specify a longer integer.
  16. Derived types • Arrays • A fixed-size sequence of elements

    of a single type, e.g., int arr[10];. • Pointers • Variables that store memory addresses of another variable, e.g., int *ptr;. • Structures • A user-defined data type that allows the combination of data items of different kinds, e.g., struct { int age; char *name; } person;. • Union • Similar to structures, but the members that share the same memory location, allowing different types of data in the same location at different times. • Function Pointers • Variables that point to functions.
  17. Modifier Types unsigned int followers = 5000; // Only positive

    numbers short int distance = 32000; // Short integer, typically 2 bytes long int population = 1000000; // Long integer, typically 4 or 8 bytes unsigned long int stars = 4294967295; // Large range positive numbers signed short temperature = -32768; // Allows for negative numbers in a small range
  18. Modifier Types #include <stdio.h> #include <math.h> int main() { unsigned

    long x = 18446744073709551615UL; printf("%lu", x); return 0; }
  19. Casting • Casting in C is a way to convert

    a variable from one data type to another. • This can be done explicitly using casting operators or implicitly by the compiler
  20. Explicit Casting • Casting in C is a way to

    convert a variable from one data type to another. • This can be done explicitly using casting operators or implicitly by the compiler • Example int i = 10; float f = (float) i; double d = 9.5; int x = (int) d; float temp = 65.99; char ch = (char) temp;
  21. Implicit Casting • Implicit casting is automatically performed by the

    compiler when passing values between different types without explicit cast • However, care must be taken as implicit casting can sometimes lead to unexpected results or data loss: • Example int i = 42; float f = i; // We do not lose information
  22. Output • The printf function in C is a standard

    output function that is used extensively for formatting and printing data to the console • int printf(const char *format, ...); • format: A format string that includes text to be printed, placeholders for variables (format specifiers), and formatting instructions. • ...: Represents a variable number of arguments that replace the format specifiers in the format string.
  23. Format Specifiers Format Specifier Description Example Value Printed Output %d

    or %i Integer in decimal base 42 42 %u Unsigned decimal integer 150 150 %f Floating-point number 3.14159 3.141590 %lf Double precision floating point (used interchangeably with %f in printf) 3.1415926535 3.141593 %e or %E Scientific notation (lowercase or uppercase) 123456.789 1.234568e+05 %g or %G Shortest representation of %f or %e (lowercase or uppercase) 0.00012345 1.2345e-04 %x or %X Unsigned hexadecimal integer (lowercase or uppercase) 255 ff or FF %o Unsigned octal integer 10 12 %c Character 65 A %s String "Hello" Hello %p Pointer address Address of x 0x7ffeefbff8d8 %% Percent sign N/A %
  24. Escape Sequences • \n: New line • \t: Horizontal tab

    • \a: Alert (bell) character • \\: Backslash • \": Double quote
  25. Input • The scanf function in C is used to

    read formatted input from the standard input, typically the keyboard. • It is one of the most common input functions in C and serves as a counterpart to printf, which is used for formatted output. • int scanf(const char *format, ...); • format: A format string that contains one or more format specifiers, which specify the type and format of the data to be read. This string also can contain literals and whitespace characters, which are used to match the input. • ...: The additional arguments must be pointers to variables where the read values are stored.
  26. Format specifiers • %d - Reads an integer. • %f

    - Reads a float. • %lf - Reads a double. • %c - Reads a single character. • %s - Reads a string until a whitespace is encountered. • %[...] - Reads a string that matches a set of characters specified within the brackets.
  27. Examples int day, month, year; printf("Enter day, month, and year:

    "); scanf("%d %d %d", &day, &month, &year); printf("Entered date is: %02d/%02d/%d\n", day, month, year);
  28. If else int number = 10; if (number > 0)

    { printf("The number is positive.\n"); } else if (number < 0) { printf("The number is negative.\n"); } else { printf("The number is zero.\n"); }
  29. switch char grade = 'B'; switch (grade) { case 'A':

    printf("Excellent!\n"); break; case 'B': case 'C': printf("Well done\n"); break; case 'D': printf("You passed\n"); break; case 'F': printf("Better try again\n"); break; default: printf("Invalid grade\n"); }
  30. while int count = 5; while (count > 0) {

    printf("Count = %d\n", count); count--; }
  31. for for (int i = 0; i < 5; i++)

    { printf("i = %d\n", i); }
  32. do while int a = 5; do { printf("a =

    %d\n", a); a--; } while (a > 0);
  33. Conditions • Conditions within if statements are evaluated as Boolean

    expressions where the integer zero (0) represents FALSE • Any non-zero value is treated as TRUE. • if(1) { .. }
  34. RAM Type Storage Location Initialization Lifetime Scope Typical Use Cases

    Local Stack Not automatic Duration of function call Limited to the block where declared Temporary data within functions Global Data Segment (.data or .bss) Automatic (zero if uninitialized) Entire program duration Accessible from any part of the program Data needed across multiple functions or modules Static (within functions) Data Segment (.data or .bss) Automatic (zero if uninitialized) Entire program duration Limited to the function/block declared Preserving state between function calls Static (global) Data Segment (.data or .bss) Automatic (zero if uninitialized) Entire program duration Limited to the file where declared Module-wide private data Dynamic Heap Not automatic Controlled by programmer Controlled by pointers Flexible size data or when amount is unknown at compile time
  35. Stack • Stack allocation is faster than heap allocation •

    Memory on the stack is automatically created when a function starts and cleaned up when the function exits • Best used for small data that will not need to be resized and for data whose lifetime is well-known and coincides with the scope of the block in which it is declared
  36. Heap • The heap is a more loosely managed pool

    of memory where blocks of memory are dynamically allocated and freed, often in an arbitrary order. • The heap can grow dynamically and is generally limited by the size of the virtual memory in the operating system. • Heap allocation involves more complex management, which can include searching for a block of free memory of adequate size, which makes it slower compared to stack allocation • The lifetime of heap variables is controlled by the programmer
  37. Stack #include <stdio.h> void function() { int stackVar = 10;

    // Local variable allocated on the stack printf("Stack variable value: %d\n", stackVar); } int main() { function(); return 0; }
  38. Pointers and references #include <stdio.h> #include <stdlib.h> int main() {

    int a = 5; printf("Address of a is %p\n", &a); int *memoryAddressOfA = &a; printf("Address is a is %p\n", memoryAddressOfA); // let's change a *memoryAddressOfA = 6; printf("Value of a is %d\n", a); return 0; }
  39. Heap #include <stdio.h> #include <stdlib.h> int main() { int *heapVar

    = malloc(sizeof(int)); // Allocate memory on the heap printf("Address is %p\n", heapVar); printf("Value is %d\n", *heapVar); *heapVar = 20; // Assign value to allocated memory printf("Heap variable value: %d\n", *heapVar); free(heapVar); // Free the allocated memory heapVar = NULL; // Good practice to set pointer to NULL after freeing return 0; }
  40. Memory Leak #include <stdio.h> #include <stdlib.h> int main() { if(1)

    { int *heapVar = malloc(sizeof(int)); // Allocate memory on the heap printf("Address is %p\n", heapVar); printf("Value is %d\n", *heapVar); *heapVar = 20; // Assign value to allocated memory printf("Heap variable value: %d\n", *heapVar); } // free(heapVar); // Free the allocated memory // heapVar = NULL; // Good practice to set pointer to NULL after freeing return 0; }
  41. Fix #include <stdio.h> #include <stdlib.h> int main() { int *heapVar

    = NULL; // Declare heapVar outside the if block if(1) { heapVar = malloc(sizeof(int)); // Allocate memory on the heap printf("Address is %p\n", heapVar); *heapVar = 20; // Assign value to allocated memory printf("Value is %d\n", *heapVar); printf("Heap variable value: %d\n", *heapVar); } // Free the allocated memory outside the if block if (heapVar != NULL) { free(heapVar); heapVar = NULL; // Good practice to set pointer to NULL after freeing } return 0; }
  42. Arrays • Arrays in C are fundamental data structures that

    consist of elements of the same data type placed contiguously in memory
  43. Array in Stack #include <stdio.h> int main() { int arr[5]

    = {1, 2, 3, 4, 5}; // Array declared on the stack int i; // Loop variable also on the stack printf("Array elements are: "); for (i = 0; i < 5; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; }
  44. Array in Heap #include <stdio.h> #include <stdlib.h> // Include for

    malloc and free functions int main() { int size = 5; int *arr = malloc(size * sizeof(int)); // Dynamically allocate memory for the array on the heap // Initialize array elements for (int i = 0; i < size; i++) { arr[i] = i + 1; // Assign values to the array } printf("Array elements are: "); for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); free(arr); // Free the allocated memory arr = NULL; // Set pointer to NULL to avoid dangling pointer return 0; }
  45. Dynamic array in heap #include <stdio.h> #include <stdlib.h> // Include

    for malloc and free functions int main() { int size; // Ask user for the size of the array printf("Enter the size of the array: "); scanf("%d", &size); int *arr = malloc(size * sizeof(int)); // Dynamically allocate memory for the array on the heap // Initialize array elements for (int i = 0; i < size; i++) { arr[i] = i + 1; // Assign values to the array } printf("Array elements are: "); for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); free(arr); // Free the allocated memory arr = NULL; // Set pointer to NULL to avoid dangling pointer return 0; }
  46. Pointers with Arrays #include <stdio.h> #include <stdlib.h> int main() {

    // Allocate memory for three integers int *numbers = malloc(3 * sizeof(int)); // Initialize the integers using pointer arithmetic *numbers = 1; // Equivalent to numbers[0] = 1 *(numbers + 1) = 2; // Equivalent to numbers[1] = 2 *(numbers + 2) = 3; // Equivalent to numbers[2] = 3 // Print the integers using pointer arithmetic printf("First integer: %d\n", *numbers); // Outputs 1 printf("Second integer: %d\n", *(numbers + 1)); // Outputs 2 printf("Third integer: %d\n", *(numbers + 2)); // Outputs 3 // Free the allocated memory free(numbers); numbers = NULL; // Good practice to set pointer to NULL after freeing return 0; }
  47. Char arrays • String: char array that ends with '\0'

    • Declaration • char str1[6] = "hello"; // Array size is 6, including the null terminator • Accessing • char firstChar = str1[0]; • Output • printf("%s\n", str1); // Output the string • Input • scanf("%s", str2); // Read a string into str2 (unsafe, prefer fgets)
  48. Avoid scanf • Using scanf to read strings into character

    arrays can be problematic due to its potential to cause buffer overflow • Buffer overflow occurs when the data written to a buffer exceeds its storage capacity, which can lead to undefined behavior, program crashes, or security vulnerabilities. • Example • char name[10]; • printf("Enter your name: "); • scanf("%s", name); // Unsafe: does not limit input size
  49. fgets #include <stdio.h> int main() { char name[10]; printf("Enter your

    name: "); fgets(name, sizeof(name), stdin); // Safe: input size is limited // Remove potential newline character name[strcspn(name, "\n")] = 0; printf("Hello, %s!\n", name); return 0; }
  50. strcspn, strlen, strcat #include <stdio.h> #include <string.h> int main() {

    char str[20]; printf("Enter a string: "); fgets(str, sizeof(str), stdin); // Read string with space handling // Replace \n with \0. \0 marks the end of the string int index = strcspn(str, "\n"); str[index] = '\0'; printf("You entered: %s\n", str); // String manipulation int len = strlen(str); printf("String length: %d\n", len); strcat(str, " World"); printf("String after concatenation: %s\n", str); return 0; }
  51. Dynamic Char Array #include <stdio.h> #include <stdlib.h> int main() {

    int size = 256; // Define the maximum size of the input char *str = malloc(size); // Dynamically allocate memory for the string printf("Enter a string: "); fgets(str, size, stdin) // Remove the newline character if present str[strcspn(str, "\n")] = '\0'; printf("You entered: %s\n", str); free(str); // Free the allocated memory return 0; }
  52. Functions • Functions are blocks of code that perform a

    specific task • Help you organize your programs by dividing them into smaller, manageable, and reusable parts • Using functions can make your code more modular, easier to maintain, and more readable.
  53. Basic Structure • Return Type: • Specifies what type of

    data the function will return. It can be any data type such as int, char, void, etc. A void return type means the function does not return a value. • Function Name: • The identifier by which the function can be called in other parts of the program. • Parameters (Optional): • Variables that accept values passed into the function. These parameters act as local variables within the function. • Function Body: • The block of code that defines what the function does. It includes a series of statements enclosed in curly braces {}. • Return Statement (Conditional): • This statement is used to return a value from the function. It is required if the function declares a return type other than void.
  54. Example #include <stdio.h> // Function declaration int multiply(int x, int

    y); int main() { int result = multiply(10, 5); printf("Result: %d\n", result); return 0; } // Function definition int multiply(int x, int y) { return x * y; // Return the product of x and y }
  55. #include <stdio.h> #include <string.h> void output(char character, int amount) {

    for(int i=0; i<amount; i++) { printf("%c", character); } } int main() { int height; printf("Enter height: "); scanf("%d", &height); for(int row = 0; row < height; row++) { if(row == 0 || row == height - 1) { output('x', height); } else { output('x', 1); output(' ', height - 2); output('x', 1); } printf("%c", '\n'); } return 0; }
  56. #include <stdio.h> #include <string.h> #define WALL_CHAR 'x' #define SPACE_CHAR '

    ' void output(char character, int amount) { for (int i = 0; i < amount; i++) { putchar(character); } } void printRow(int width, int isBorder) { if (isBorder) { output(WALL_CHAR, width); } else { output(WALL_CHAR, 1); output(SPACE_CHAR, width - 2); output(WALL_CHAR, 1); } putchar('\n'); } int main() { int height; printf("Enter height: "); if (scanf("%d", &height) != 1 || height <= 0) { printf("Invalid input. Please enter a positive integer.\n"); return 1; } for (int row = 0; row < height; row++) { printRow(height, row == 0 || row == height - 1); } return 0; } Preprocessor commands for creating constant values putchar is easier function for outputting only one char
  57. Structs • Structs in C programming are composite data types

    that allow you to encapsulate multiple data items of potentially different types into a single cohesive unit. • Composite Type: • A struct (short for "structure") is a user-defined data type in C that groups together different data items (called members) under a single name. • Encapsulation: • Structs help in encapsulating related data items, making it easier to manage and organize data in complex programs.
  58. Example struct Person { char name[50]; int age; float height;

    }; struct Person person1 = {"John Doe", 30, 5.75};
  59. Example struct Person person1; strcpy(person1.name, "Alice"); person1.age = 28; struct

    Person *ptr = &person1; printf("Name: %s, Age: %d", ptr->name, ptr- >age);
  60. Example struct Person { char name[50]; int age; float height;

    }; struct Person person1 = {"John Doe", 30, 5.75};
  61. Example struct Person *p = malloc(sizeof(struct Person)); if (p !=

    NULL) { strcpy(p->name, "Bob"); p->age = 40; }
  62. C++

  63. Origin and History • Developed by Bjarne Stroustrup in 1979

    • Extension of C with object-oriented features • Standardized by ISO in 1998 (C++98) with several updates (C++03, C++11, C++14, C++17, C++20)
  64. Syntax and Structure • Similarities with C • Basic syntax:

    statements, expressions, control structures (if, for, while) • Primitive data types: int, char, float, double • Functions and pointers • Differences from C • Classes and objects • Access specifiers: public, private, protected • Constructors and destructors • Inline functions
  65. Fundamental Data Types • int: Integer type • char: Character

    type • float: Single precision floating-point type • double: Double precision floating-point type • bool: Boolean type (true/false)
  66. Header files • Declarations: • Header files are used to

    declare the interfaces to your code, including functions, classes, constants, and macros. • Inclusions: • They are included in other files using the #include directive to share declarations across multiple source files without redefining them.
  67. mymath.h #ifndef MYMATH_H #define MYMATH_H namespace mymath { int max(int

    a, int b); } #endif rPevents multiple inclusions of the same header file using
  68. Source files: .cpp • Provides the body of the functions

    declared in the header files. • Class Method Definitions: Implements the methods of the classes declared in the header files. • Local Functions: Defines any additional functions that are not exposed to other parts of the program.
  69. mymath.cpp #include "mymath.h" namespace mymath { int max(int a, int

    b) { return a > b ? a : b; } } Ensure that header file is consistant with cpp file
  70. main.cpp #include <iostream> #include "mymath.h" int main() { std::cout <<

    "Hello, World!" << std::endl; std::cout << mymath::max(5, 5) << std::endl; return 0; }
  71. Namespaces #include <iostream> #include "mymath1.h" #include "mymath2.h" int main() {

    std::cout << mymath1::max(5, 5) << std::endl; std::cout << mymath2::max(5, 5) << std::endl; return 0; } Possible to have max – method in two different namespaces, no name collisions
  72. IOStream • Including the iostream Library • Output with cout

    • std::cout << "Hello, World!" << std::endl; • Input with cin • int age; • std::cout << "Enter your age: "; • std::cin >> age;
  73. Function in C++ • A function is a block of

    code that performs a specific task. • Functions help in code reusability and modularity. • Function • int add(int a, int b) { • return a + b; • }
  74. Function Overloading • Function overloading allows multiple functions to have

    the same name with different parameters. • It helps improve code readability and usability. • Functions must differ in the type or number of parameters. • Return type alone is not sufficient to overload a function.
  75. Example int add(int a, int b) { return a +

    b; } double add(double a, double b) { return a + b; }
  76. Default parameters void display(int a, int b = 10) {

    std::cout << "a: " << a << ", b: " << b << std::endl; } display(5); // Output: a: 5, b: 10 display(5, 20); // Output: a: 5, b: 20
  77. Example void greet(std::string name = "Guest") { std::cout << "Hello,

    " << name << "!" << std::endl; } void greet(std::string name, std::string title) { std::cout << "Hello, " << title << " " << name << "!" << std::endl; } greet(); // Output: Hello, Guest! greet("Alice"); // Output: Hello, Alice! greet("Alice", "Dr."); // Output: Hello, Dr. Alice!
  78. Classes and Objects // Class definition class Animal { public:

    void eat() { std::cout << "I can eat!" << std::endl; } }; // Creating an object int main() { Animal animal1; animal1.eat(); // Output: I can eat! return 0; }
  79. class Student { private: std::string name; int age; public: //

    Setter for name void setName(std::string n) { name = n; } // Getter for name std::string getName() { return name; } // Setter for age void setAge(int a) { age = a; } // Getter for age int getAge() { return age; } }; int main() { Student student1; student1.setName("Alice"); student1.setAge(20); std::cout << "Name: " << student1.getName() << std::endl; std::cout << "Age: " << student1.getAge() << std::endl; return 0; }
  80. Inheritance // Base class class Animal { public: void eat()

    { std::cout << "I can eat!" << std::endl; } }; // Derived class class Dog : public Animal { public: void bark() { std::cout << "I can bark!" << std::endl; } }; int main() { Dog dog1; dog1.eat(); // Output: I can eat! dog1.bark(); // Output: I can bark! return 0; }
  81. Polymorphism // Base class class Shape { public: virtual void

    draw() { std::cout << "Drawing Shape" << std::endl; } }; // Derived class class Circle : public Shape { public: void draw() override { std::cout << "Drawing Circle" << std::endl; } }; int main() { Shape* shape1 = new Shape(); Shape* shape2 = new Circle(); shape1->draw(); // Output: Drawing Shape shape2->draw(); // Output: Drawing Circle delete shape1; delete shape2; return 0; }
  82. Abstract class // Base class class Shape { public: virtual

    void draw() = 0; }; // Derived class class Circle : public Shape { public: void draw() override { std::cout << "Drawing Circle" << std::endl; } }; int main() { Shape* shape1 = new Shape(); Shape* shape2 = new Circle(); shape1->draw(); // Output: Drawing Shape shape2->draw(); // Output: Drawing Circle delete shape1; delete shape2; return 0; }
  83. Using heap with int #include <iostream> int main() { //

    Step 1: Allocate memory on the heap int* ptr = new int; // Step 2: Assign a value to the allocated memory *ptr = 42; // Step 3: Use the allocated memory std::cout << "Value: " << *ptr << std::endl; // Step 4: Deallocate the memory delete ptr; ptr = nullptr; // Avoid dangling pointer return 0; }
  84. Memory leak #include <iostream> int main() { // Step 1:

    Allocate memory on the heap int* ptr = nullptr; if (true) { // The condition is always true, but it could be any condition ptr = new int; // Step 2: Assign a value to the allocated memory *ptr = 42; // Step 3: Use the allocated memory std::cout << "Value: " << *ptr << std::endl; // Memory leak here: No delete statement to deallocate the memory // The allocated memory is never freed } // Outside the if block, there is no delete statement // ptr still points to the allocated memory but it's not deallocated return 0; }
  85. Templates • Templates in C++ are a powerful feature that

    allows for generic programming. • Enable functions and classes to operate with any data type without being rewritten for each type • There are two basic main types of templates • function templates • class templates
  86. Function Template #include <iostream> // Function template template <typename T>

    T add(T a, T b) { return a + b; } int main() { int intResult = add(3, 4); // T is int double doubleResult = add(2.5, 3.1); // T is double std::cout << "intResult: " << intResult << std::endl; // Outputs: intResult: 7 std::cout << "doubleResult: " << doubleResult << std::endl; // Outputs: doubleResult: 5.6 return 0; }
  87. Class Template #include <iostream> // Class template template <typename T>

    class Container { private: T value; public: Container(T val) : value(val) {} void setValue(T val) { value = val; } T getValue() { return value; } }; int main() { Container<int> intContainer(42); // T is int Container<double> doubleContainer(3.14); // T is double std::cout << "intContainer: " << intContainer.getValue() << std::endl; // Outputs: intContainer: 42 std::cout << "doubleContainer: " << doubleContainer.getValue() << std::endl; // Outputs: doubleContainer: 3.14 return 0; }
  88. #include <iostream> #include <list> int main() { // Create a

    list of integers on the heap std::list<int>* myList = new std::list<int>; // Insert elements into the list myList->push_back(10); // Add 10 to the end myList->push_back(20); // Add 20 to the end myList->push_back(30); // Add 30 to the end // Print the list elements std::cout << "List elements: "; for (int value : *myList) { std::cout << value << " "; } std::cout << std::endl; // Insert at the front myList->push_front(5); // Add 5 to the front // Print the list elements again std::cout << "List elements after push_front: "; for (int value : *myList) { std::cout << value << " "; } std::cout << std::endl; // Delete an element by value myList->remove(20); // Remove 20 from the list // Print the list elements again std::cout << "List elements after removal: "; for (int value : *myList) { std::cout << value << " "; } std::cout << std::endl; // Access the first and last elements std::cout << "First element: " << myList->front() << std::endl; std::cout << "Last element: " << myList->back() << std::endl; // Free the memory allocated for the list delete myList; return 0; } // g++ -std=c++11 *.cpp -o myapp
  89. auto type #include <iostream> #include <vector> int main() { auto

    x = 5; // int auto y = 3.14; // double auto str = "Hello"; // const char* std::vector<int> vec = {1, 2, 3, 4, 5}; for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } std::cout << std::endl; return 0; }
  90. range #include <iostream> #include <vector> int main() { std::vector<int> vec

    = {1, 2, 3, 4, 5}; for (int value : vec) { std::cout << value << " "; } std::cout << std::endl; return 0; }
  91. Smart Pointers • unique_ptr represents unique ownership of a resource.

    • Only one unique_ptr can own a resource at a time • When the unique_ptr goes out of scope, it automatically deletes the resource. • shared_ptr allows multiple pointers to share ownership of a resource. • The resource is deleted when the last shared_ptr owning it is destroyed.
  92. Problem #include <iostream> int main() { if (true) { int*

    ptr = new int(10); // Allocate memory on the heap std::cout << "Value: " << *ptr << std::endl; // Forgetting to delete the allocated memory } // Memory allocated inside the if block is not freed, causing a memory leak return 0; }
  93. Fix: g++ -std=c++14 *.cpp -o myapp #include <iostream> #include <memory>

    int main() { if (true) { std::unique_ptr<int> ptr = std::make_unique<int>(10); // Allocate memory on the heap using unique_ptr std::cout << "Value: " << *ptr << std::endl; // No need to manually delete, unique_ptr automatically deletes the memory when it goes out of scope } // Memory allocated inside the if block is automatically freed when the unique_ptr goes out of scope return 0; }
  94. shared_ptr #include <iostream> #include <memory> // For shared_ptr class MyClass

    { public: MyClass(int value) : value(value) { std::cout << "MyClass constructor called with value: " << value << std::endl; } ~MyClass() { std::cout << "MyClass destructor called for value: " << value << std::endl; } int getValue() const { return value; } private: int value; }; int main() { std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(42); if(true) { std::shared_ptr<MyClass> ptr2 = ptr1; std::cout << "Value through ptr2: " << ptr2->getValue() << std::endl; std::cout << "Reference count: " << ptr1.use_count() << std::endl; } std::cout << "Value through ptr1: " << ptr1->getValue() << std::endl; std::cout << "Reference count: " << ptr1.use_count() << std::endl; return 0; }
  95. Lambdas • An anonymous function that can capture variables from

    its surrounding scope. • Basic Syntax: • [ capture ] ( params ) -> ret { body } • Capture Clause ([]): Specifies which variables from the surrounding scope are captured and how. • Parameter List (( params )): Defines the parameters the lambda takes. • Return Type (-> ret) (optional): Specifies the return type. If omitted, the compiler deduces it. • Body ({ body }): Contains the code to be executed when the lambda is called.
  96. Example #include <iostream> #include <functional> int main() { // Define

    the lambda function with std::function std::function<int(int, int)> add = [](int a, int b) -> int { return a + b; }; // Use the lambda function to add two numbers int sum = add(5, 3); // Print the result std::cout << "The sum of 5 and 3 is: " << sum << std::endl; return 0; }
  97. Using auto #include <iostream> int main() { // Define the

    lambda function auto add = [](int a, int b) -> int { return a + b; }; // Use the lambda function to add two numbers int sum = add(5, 3); // Print the result std::cout << "The sum of 5 and 3 is: " << sum << std::endl; return 0; }
  98. Using callbacks #include <iostream> #include <functional> // Function that takes

    two integers and a callback function void performOperation(int a, int b, const std::function<int(int, int)>& callback) { // Call the callback function with the provided integers int result = callback(a, b); // Print the result std::cout << "The result of the operation is: " << result << std::endl; } int main() { // Define the lambda function for summing two numbers auto sum = [](int a, int b) -> int { return a + b; }; // Define the lambda function for subtracting two numbers auto extract = [](int a, int b) -> int { return a - b; }; // Use the lambda function for summing as a callback performOperation(5, 3, sum); // Should print "The result of the operation is: 8" // Use the lambda function for extracting as a callback performOperation(5, 3, extract); // Should print "The result of the operation is: 2" return 0; }
  99. Using callbacks with anonymous lambdas #include <iostream> #include <functional> //

    Function that takes two integers and a callback function void performOperation(int a, int b, const std::function<int(int, int)>& callback) { // Call the callback function with the provided integers int result = callback(a, b); // Print the result std::cout << "The result of the operation is: " << result << std::endl; } int main() { // Use an anonymous lambda function for summing as a callback performOperation(5, 3, [](int a, int b) -> int { return a + b; }); // Should print "The result of the operation is: 8" // Use an anonymous lambda function for subtracting as a callback performOperation(5, 3, [](int a, int b) -> int { return a - b; }); // Should print "The result of the operation is: 2" return 0; }
  100. #include <iostream> #include <fstream> #include <string> #include <thread> #include <functional>

    // Function that reads a file in a different thread and invokes the callback with the file content void fileRead(const std::string& filePath, std::function<void(const std::string&)> callback) { // Create a thread to read the file std::thread([filePath, callback]() { std::ifstream inputFile(filePath); if (!inputFile) { std::cerr << "Unable to open file: " << filePath << std::endl; return; } std::string content; std::string line; while (std::getline(inputFile, line)) { content += line + '\n'; } inputFile.close(); // Invoke the callback with the file content callback(content); }).detach(); } int main() { // Example usage of fileRead function fileRead("path/to/foo.txt", [](const std::string& content) { std::cout << "File content:\n" << content << std::endl; }); // Prevent main from exiting immediately std::this_thread::sleep_for(std::chrono::seconds(2)); // Adjust time as needed for file reading to complete return 0; } allows the thread to run independently from the std::thread object that originally represented it. After calling detach, the thread becomes a daemon thread