Introduction to C++

C++ is a powerful, general-purpose programming language that extends C with object-oriented and generic programming features. It’s widely used for system programming, game development, and high-performance applications due to its efficiency and control over hardware.

This tutorial assumes basic knowledge of computers and introduces C++ concepts step-by-step, from variables to object-oriented programming, with practical examples.

  • C++ supports procedural, object-oriented, and generic programming.
  • It’s used in applications like game engines (e.g., Unreal Engine) and operating systems.
  • Compilers like g++ or clang++ are needed to run C++ code.
  • The Standard Template Library (STL) provides reusable components like vectors.
  • This guide assumes basic computer knowledge and introduces C++ step-by-step.
Variables and basic data types

Variables store data in a C++ program. They must be declared with a specific type: int age = 25; // Integer double price = 19.99; // Floating-point char grade = 'A'; // Character bool isActive = true; // Boolean std::string name = "Alice"; // String (requires <string> header)

Identifiers must start with a letter or underscore, followed by letters, digits, or underscores. C++ is case-sensitive.

  • int for whole numbers like 25 or -10.
  • double for decimals like 19.99.
  • char for single characters like 'A'.
  • bool for true/false values.
  • std::string for text, requires <string> header.
Const

The const keyword declares immutable variables: const double PI = 3.14159;

Constants must be initialized at declaration and cannot be modified. constexpr ensures compile-time evaluation: constexpr int MAX = 100;

  • Constants like PI cannot be changed after initialization.
  • constexpr for compile-time constants like MAX.
  • Follows same naming rules as variables.
  • Prevents accidental modification of critical values.
  • Cannot share names with variables in the same scope.
Namespaces

Namespaces prevent name conflicts by grouping code: namespace mySpace { int x = 10; } int main() { std::cout << mySpace::x; // Access with scope resolution return 0; }

Use using namespace std; to avoid std:: prefixes, but sparingly to avoid conflicts.

  • Groups related code to avoid naming conflicts.
  • Access with :: operator, e.g., mySpace::x.
  • std namespace includes standard library.
  • using namespace can simplify code but risks conflicts.
  • Supports nested namespaces for complex projects.
Typedef and type aliases

typedef creates aliases for types: typedef unsigned long ulong;

C++11’s using is more flexible: using str = std::string; str name = "Bob";

  • typedef simplifies complex type names.
  • using is preferred in modern C++.
  • Improves code readability.
  • Useful for function pointers or templates.
  • Can alias any type, including classes.
Arithmetic operators

C++ supports operators like +, -, *, /, and % (modulus): int a = 10, b = 3; int sum = a + b; // 13 int mod = a % b; // 1

Increment (++) and decrement (--) modify variables: a++; // a = 11

  • Addition: a + b for summing values.
  • Subtraction: a - b for differences.
  • Multiplication: a * b for products.
  • Division: a / b, integer division truncates.
  • Modulus: a % b for remainders.
Type conversion

Convert between types explicitly with casts: double d = 5.7; int i = static_cast<int>(d); // i = 5

Implicit conversion occurs in mixed-type operations: int x = 10; double y = x; // y = 10.0

  • Explicit casting with static_cast.
  • Implicit conversion in assignments or expressions.
  • May lose precision (e.g., double to int).
  • dynamic_cast for polymorphic types.
  • C-style casts ((int)d) are less safe.
User input

Use std::cin to read input: #include <iostream> int main() { int num; std::cout << "Enter a number: "; std::cin >> num; return 0; }

Read strings with std::getline: #include <string> std::string name; std::getline(std::cin, name);

  • std::cin reads space-separated input.
  • std::getline reads entire lines.
  • Requires <iostream> for input/output.
  • Check errors with std::cin.fail().
  • Use std::cin.ignore() to clear input buffer.
If statements

Execute code if a condition is true: if (x > 0) { std::cout << "Positive"; } else if (x < 0) { std::cout << "Negative"; } else { std::cout << "Zero"; }

  • Basic if checks a condition.
  • else if handles additional conditions.
  • else covers all other cases.
  • Use braces for multiple statements.
  • Conditions must evaluate to true/false.
Switches

switch evaluates a variable against cases: switch (day) { case 1: std::cout << "Monday"; break; default: std::cout << "Unknown"; }

Use break to prevent fall-through.

  • Compares variable to case values.
  • break exits the switch block.
  • default handles unmatched cases.
  • Works with int, char, etc.
  • More readable than chained if-else.
Ternary operator

A shorthand for if-else: int max = (a > b) ? a : b;

  • Syntax: condition ? valueIfTrue : valueIfFalse.
  • Concise for simple conditions.
  • Returns a value, unlike if.
  • Avoid nesting for readability.
  • Useful in assignments or expressions.
Logical operators

Combine conditions with && (and), || (or), ! (not): if (x > 0 && y > 0) { std::cout << "Both positive"; }

  • && requires both conditions true.
  • || requires at least one true.
  • ! inverts truth value.
  • Short-circuit evaluation optimizes checks.
  • Used in complex conditionals.
Useful string methods in C++

The std::string class offers methods: std::string s = "Hello"; int len = s.length(); // 5 s.append(" World"); // "Hello World" char c = s.at(0); // 'H'

  • length() returns string length.
  • append() adds text to end.
  • at() accesses characters safely.
  • substr() extracts substrings.
  • find() locates text position.
While loops

Execute while a condition is true: int i = 0; while (i < 5) { std::cout << i++; }

  • Checks condition before each iteration.
  • Executes only if condition is true.
  • Risk of infinite loops if condition persists.
  • Use braces for multiple statements.
  • Common for dynamic iteration counts.
Do while loops

Execute at least once, then continue if true: int i = 0; do { std::cout << i++; } while (i < 5);

  • Executes at least once.
  • Condition checked after iteration.
  • Useful for input validation loops.
  • Braces for multiple statements.
  • Can become infinite if condition persists.
For loops

Loop with initialization, condition, and update: for (int i = 0; i < 5; i++) { std::cout << i; }

  • Initialization runs once.
  • Condition checked before each iteration.
  • Update runs after each iteration.
  • Ideal for fixed iteration counts.
  • Combines loop control in one line.
Break & continue

break exits a loop; continue skips to the next iteration: for (int i = 0; i < 5; i++) { if (i == 3) break; // Exits loop if (i == 1) continue; // Skips 1 std::cout << i; }

  • break stops loop immediately.
  • continue skips current iteration.
  • Works in all loop types.
  • Useful for conditional loop control.
  • Can improve loop efficiency.
Nested loops

Loops within loops: for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { std::cout << i << j; } }

  • Inner loop runs fully for each outer iteration.
  • Used for multidimensional data.
  • Can be computationally intensive.
  • break affects innermost loop.
  • Common in matrix operations.
Arrays

Arrays store fixed-size sequences: int numbers[5] = {1, 2, 3, 4, 5};

  • Fixed size set at declaration.
  • Access via zero-based index.
  • Initialize with values or default to 0.
  • Out-of-bounds access is undefined.
  • Used for sequential data storage.
Sizeof() operator

Returns the size of a type or variable in bytes: int arr[5]; int size = sizeof(arr); // 20 (5 ints * 4 bytes)

  • Works with types or variables.
  • Array size: sizeof(arr) / sizeof(arr[0]).
  • Size varies by architecture.
  • Useful for loop bounds.
  • Evaluated at compile time.
Iterate over an array

Use a loop to access array elements: int arr[3] = {1, 2, 3}; for (int i = 0; i < 3; i++) { std::cout << arr[i]; }

  • Use for or while loops.
  • Access via index: arr[i].
  • Avoid hardcoding array size.
  • Check bounds to prevent errors.
  • Can modify elements during iteration.
Foreach loop

Range-based for loop (C++11): int arr[3] = {1, 2, 3}; for (int num : arr) { std::cout << num; }

  • Simplifies array iteration.
  • Works with containers like std::vector.
  • Use auto for type deduction.
  • Read-only unless using references.
  • Introduced in C++11.
Pass array to a function

Arrays are passed as pointers: void printArray(int arr[], int size) { for (int i = 0; i < size; i++) { std::cout << arr[i]; } }

  • Pass size explicitly.
  • Modifications affect original array.
  • Use const to prevent changes.
  • Pointer decay occurs in functions.
  • Call with array name: printArray(arr, 5).
Search an array for an element

Linear search example: int find(int arr[], int size, int target) { for (int i = 0; i < size; i++) { if (arr[i] == target) return i; } return -1; }

  • Returns index or -1 if not found.
  • Works with unsorted arrays.
  • Linear time complexity.
  • Use std::find for standard solution.
  • Binary search faster for sorted arrays.
Sort an array

Use std::sort from <algorithm>: #include <algorithm> int arr[5] = {5, 2, 8, 1, 9}; std::sort(arr, arr + 5);

  • Sorts ascending by default.
  • Custom comparators for other orders.
  • Requires <algorithm>.
  • Efficient for large datasets.
  • Modifies array in place.
Fill() function

Use std::fill to set array elements: #include <algorithm> int arr[5]; std::fill(arr, arr + 5, 0); // Fills with 0

  • Sets range to specified value.
  • Requires <algorithm>.
  • Works with any container.
  • Faster than manual loops.
  • Specify start and end iterators.
Fill an array with user input

Read user input into an array: int arr[3]; for (int i = 0; i < 3; i++) { std::cin >> arr[i]; }

  • Uses std::cin for input.
  • Loop over array indices.
  • Validate input to avoid errors.
  • Combine with prompts for clarity.
  • Clear buffer with std::cin.ignore().
Multidimensional arrays

Arrays of arrays, e.g., 2D: int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};

  • Used for grids or matrices.
  • Access: matrix[0][1].
  • Fixed size per dimension.
  • Requires nested loops for iteration.
  • Stored contiguously in memory.
Memory addresses

Use & to get a variable’s address: int x = 10; std::cout << &x; // Prints memory address

  • Addresses are hexadecimal.
  • Unique per variable.
  • Used with pointers.
  • Changes each program run.
  • Fundamental for memory management.
Pass by VALUE vs pass by REFERENCE

Pass by value copies; pass by reference modifies: void byValue(int x) { x++; } void byReference(int& x) { x++; }

  • Value copying preserves original.
  • Reference modifies original.
  • References use & in signature.
  • References are efficient for large data.
  • Use const for read-only references.
Const parameters

Prevent modification of parameters: void print(const int& x) { std::cout << x; }

  • Ensures parameter integrity.
  • Common with references.
  • Also works with pointers.
  • Improves code safety.
  • Allows compiler optimizations.
Pointers

Store memory addresses: int x = 10; int* ptr = &x; std::cout << *ptr; // Dereference to get 10

  • Declared with *.
  • Dereference with *.
  • Points to specific types.
  • Used for dynamic memory.
  • Requires careful handling.
Null pointers

Pointers not pointing anywhere: int* ptr = nullptr;

  • Uses nullptr (C++11).
  • Prevents undefined behavior.
  • Check before dereferencing.
  • Safer than NULL.
  • Initializes unassigned pointers.
Dynamic memory

Allocate memory with new, free with delete: int* ptr = new int(10); delete ptr;

  • new allocates at runtime.
  • delete frees memory.
  • Prevents memory leaks.
  • Used for dynamic data structures.
  • Manage to avoid dangling pointers.
Recursion

Functions calling themselves: int factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1); }

  • Requires base case.
  • Useful for hierarchical problems.
  • Can be memory-intensive.
  • Alternative to iteration.
  • Stack overflow risk for deep recursion.
Function templates

Generic functions for multiple types: template <typename T> T max(T a, T b) { return (a > b) ? a : b; }

  • Uses template keyword.
  • Works with any type.
  • Reduces code duplication.
  • Compile-time type safety.
  • Used in STL containers.
Structs

Group related data: struct Person { std::string name; int age; };

  • Public members by default.
  • Create instances: Person p;.
  • Access with dot operator.
  • Simpler than classes.
  • Can include methods.
Pass structs as arguments

Pass structs by reference for efficiency: void printPerson(const Person& p) { std::cout << p.name << ", " << p.age; }

  • Reference avoids copying.
  • const prevents modification.
  • Access members with dot operator.
  • Efficient for large structs.
  • Common in function arguments.
Enums

Define named integer constants: enum Color { RED, GREEN, BLUE }; Color c = RED;

  • Defaults to int type.
  • Improves code readability.
  • Values start at 0 by default.
  • Scoped enums: enum class.
  • Used for fixed option sets.
Object Oriented Programming

C++ supports OOP with classes: class Car { public: std::string model; void drive() { std::cout << "Driving"; } };

  • Encapsulation hides data.
  • Classes define objects.
  • Supports inheritance.
  • Methods define behavior.
  • Polymorphism via virtual functions.
Constructors

Initialize objects: class Car { public: std::string model; Car(std::string m) : model(m) {} };

  • Called on object creation.
  • Can take parameters.
  • Initializer lists for efficiency.
  • No return type.
  • Matches class name.
Constructor overloading

Multiple constructors with different parameters: class Car { public: std::string model; int year; Car(std::string m) : model(m), year(0) {} Car(std::string m, int y) : model(m), year(y) {} };

  • Different parameter lists.
  • Flexible object creation.
  • Compiler selects based on arguments.
  • Reduces code duplication.
  • Can call other constructors.
Getters & setters

Control access to class members: class Car { private: std::string model; public: void setModel(std::string m) { model = m; } std::string getModel() { return model; } };

  • Getters retrieve private data.
  • Setters validate and set data.
  • Enforces encapsulation.
  • Protects class invariants.
  • Common in OOP design.
Inheritance

Classes inherit properties and methods: class Vehicle { public: std::string brand; }; class Car : public Vehicle { public: std::string model; };

  • Derived class inherits base class.
  • public inheritance preserves access.
  • Supports polymorphism.
  • protected for derived access.
  • Multiple inheritance is possible.
Reference