C++ Tutorial

C++ is a general-purpose, high-performance programming language with low-level memory control and high-level OOP features. It's used for systems programming, game engines, embedded systems, competitive programming, and performance-critical applications.

Syntax & Structure

C++
#include <iostream>
#include <string>
using namespace std;

int main() {
    // Output
    cout << "Hello, World!" << endl;
    cerr << "Error message" << endl;  // stderr

    // Input
    string name;
    cout << "Enter name: ";
    cin  >> name;
    cin.ignore();                        // clear newline
    getline(cin, name);                  // read full line

    cout << "Hello, " << name << "!\n";
    return 0;  // 0 = success
}

// Compile and run
// g++ -std=c++17 -o hello main.cpp
// ./hello
► Try It Yourself

Data Types

TypeSizeExample
int4 bytesint n = 42;
long long8 byteslong long big = 1e18;
float4 bytesfloat f = 3.14f;
double8 bytesdouble d = 3.14;
char1 bytechar c = 'A';
bool1 bytebool ok = true;
stringvariablestring s = "hello";
autodeducedauto x = 42.0;

Pointers & References

C++
int x = 10;

// Pointer - stores memory address
int* ptr = &x;   // &x = address of x
cout << ptr;     // prints address (e.g. 0x7ffff...)
cout << *ptr;    // dereference: prints 10
*ptr = 20;       // modifies x through pointer
cout << x;       // 20

// Reference - alias for a variable
int& ref = x;    // ref is another name for x
ref = 30;
cout << x;       // 30

// Pointer arithmetic
int arr[] = {10, 20, 30};
int* p = arr;
cout << *(p + 1);  // 20

// nullptr (C++11)
int* np = nullptr;
if (np) { ... } // safe null check

// const pointer vs pointer to const
const int* cp  = &x;  // cannot change value: *cp = 5; // error
int* const pc  = &x;  // cannot change address: pc = &y; // error
const int* const cpc = &x; // neither
► Try It Yourself

Functions

C++
// Basic function
int add(int a, int b) { return a + b; }

// Default parameters
int power(int base, int exp = 2) {
    int result = 1;
    for (int i = 0; i < exp; i++) result *= base;
    return result;
}

// Pass by reference (modify original)
void swap(int& a, int& b) {
    int temp = a; a = b; b = temp;
}

// Pass by const reference (read-only, no copy)
void print(const string& s) { cout << s; }

// Function overloading
double add(double a, double b) { return a + b; }
string add(string a, string b) { return a + b; }

// Inline function (hint to compiler)
inline int square(int x) { return x * x; }

// Template function
template <typename T>
T maxOf(T a, T b) { return (a > b) ? a : b; }
maxOf(3, 5);           // int
maxOf(3.14, 2.71);     // double
maxOf(string("a"), string("b")); // string

// Variadic template (C++11)
template<typename... Args>
void printAll(Args... args) { (cout << ... << args) << "\n"; }
► Try It Yourself

Classes & Objects

C++
class Animal {
private:
    string name;
    int age;

public:
    // Constructor with initializer list
    Animal(string name, int age) : name(name), age(age) {}

    // Destructor
    ~Animal() { cout << name << " destroyed\n"; }

    // Getters
    string getName() const { return name; }
    int    getAge()  const { return age;  }

    // Virtual method (for polymorphism)
    virtual string speak() const { return name + " makes a sound"; }

    // Operator overloading
    bool operator==(const Animal& other) const {
        return name == other.name;
    }

    // Friend function
    friend ostream& operator<<(ostream& os, const Animal& a) {
        return os << a.name << " (age " << a.age << ")";
    }
};

// Inheritance
class Dog : public Animal {
private:
    string breed;

public:
    Dog(string name, int age, string breed)
        : Animal(name, age), breed(breed) {}

    string speak() const override {
        return getName() + " says Woof!";
    }
};

// Usage
Dog d("Rex", 3, "Labrador");
cout << d << "\n";       // Rex (age 3)
cout << d.speak() << "\n"; // Rex says Woof!

// Polymorphism - base pointer to derived object
Animal* a = new Dog("Buddy", 2, "Beagle");
cout << a->speak();  // calls Dog::speak (virtual dispatch)
delete a;
► Try It Yourself

STL Containers

C++
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <queue>
#include <stack>
#include <algorithm>

// vector (dynamic array)
vector<int> v = {3, 1, 4, 1, 5};
v.push_back(9);
v.pop_back();
v[0];              // 3
v.size();          // 5
v.empty();         // false
v.front(); v.back();
sort(v.begin(), v.end());        // ascending
sort(v.begin(), v.end(), greater<int>()); // descending

// map (sorted key-value pairs)
map<string, int> scores;
scores["Alice"] = 95;
scores["Bob"]   = 82;
for (auto& [key, val] : scores) { // structured bindings (C++17)
    cout << key << ": " << val;
}

// unordered_map (hash map, O(1) average)
unordered_map<string, int> freq;
freq["apple"]++; freq["banana"]++;

// set (sorted unique values)
set<int> s = {1, 2, 2, 3};   // {1, 2, 3}

// queue (FIFO)
queue<int> q;
q.push(1); q.push(2);
q.front();   // 1
q.pop();     // removes 1

// stack (LIFO)
stack<int> st;
st.push(5); st.push(10);
st.top();    // 10
st.pop();

// Algorithms
vector<int> nums = {5, 3, 8, 1};
sort(nums.begin(), nums.end());
auto it = lower_bound(nums.begin(), nums.end(), 3); // binary search
int  mx = *max_element(nums.begin(), nums.end());
int  sum = accumulate(nums.begin(), nums.end(), 0);
► Try It Yourself

Smart Pointers (C++11+)

C++
#include <memory>

// unique_ptr - exclusive ownership, auto-deleted
unique_ptr<int> up = make_unique<int>(42);
cout << *up;      // 42
// deleted automatically when goes out of scope

// shared_ptr - shared ownership, reference counted
shared_ptr<string> sp1 = make_shared<string>("hello");
shared_ptr<string> sp2 = sp1;  // both own the string
cout << sp1.use_count();  // 2
// deleted when last shared_ptr goes out of scope

// weak_ptr - non-owning reference (avoid circular refs)
weak_ptr<string> wp = sp1;
if (auto locked = wp.lock()) {  // check if still alive
    cout << *locked;
}
► Try It Yourself
Best Practice: Prefer smart pointers over raw new/delete in modern C++. Use unique_ptr by default, shared_ptr when shared ownership is needed.

Memory Management

C++ gives you direct control over memory, which is powerful but dangerous if you ignore ownership rules.

  • Prefer stack allocation where possible.
  • Use std::vector, std::string, and RAII types instead of manual arrays.
  • Prefer std::unique_ptr and std::shared_ptr over raw owning pointers.
  • Avoid memory leaks, double deletes, and dangling pointers.

Algorithms Library

The Standard Library includes algorithms that are faster to write and easier to review than hand-coded loops.

C++
#include <algorithm>
#include <vector>

std::vector<int> scores{4, 8, 1, 7, 3};
std::sort(scores.begin(), scores.end());

bool hasEight = std::find(scores.begin(), scores.end(), 8) != scores.end();

Build & Debug

Students should understand how code becomes an executable: preprocessing, compiling, linking, then debugging when things go wrong.

Terminal
g++ -std=c++20 -Wall -Wextra main.cpp -o app
./app