C++ Programming Tutorial

Learn modern C++ step-by-step — from basics to advanced features like templates, STL, and smart pointers. Clear explanations with practical, runnable examples.

C++ Functions

Functions encapsulate reusable logic. C++ functions have a return type, name, and parameter list. The language supports overloading, default arguments, pass by value/reference, and lambda expressions.

Defining and Calling Functions

basics.cpp
#include <iostream>
#include <string>

// Function declaration (prototype)
int add(int a, int b);
std::string greet(const std::string& name);

int main() {
    std::cout << add(3, 5) << "
";        // 8
    std::cout << greet("Alice") << "
";   // Hello, Alice!
    return 0;
}

// Function definitions
int add(int a, int b) {
    return a + b;
}

std::string greet(const std::string& name) {
    return "Hello, " + name + "!";
}

Pass by Value, Reference, and const Reference

passing.cpp
#include <iostream>
#include <vector>

// Pass by value — copies the argument (safe but may be slow for large objects)
void by_value(int x) {
    x = 99;  // does NOT affect the original
}

// Pass by reference — modifies the original
void by_reference(int& x) {
    x = 99;  // DOES affect the original
}

// Pass by const reference — read-only, no copy (best for large objects)
void print_vector(const std::vector<int>& v) {
    for (int n : v) std::cout << n << " ";
    std::cout << "
";
}

int main() {
    int a = 10;
    by_value(a);
    std::cout << a << "
";  // 10 (unchanged)

    by_reference(a);
    std::cout << a << "
";  // 99 (changed)

    std::vector<int> nums{1, 2, 3, 4, 5};
    print_vector(nums);  // no copy, cannot modify

    return 0;
}

Function Overloading

overloading.cpp
#include <iostream>
#include <string>

// Same name, different parameter types — compiler picks the right one
int max_val(int a, int b) { return (a > b) ? a : b; }
double max_val(double a, double b) { return (a > b) ? a : b; }
std::string max_val(const std::string& a, const std::string& b) {
    return (a.size() > b.size()) ? a : b;
}

int main() {
    std::cout << max_val(3, 7) << "
";           // 7 (int version)
    std::cout << max_val(3.14, 2.71) << "
";    // 3.14 (double version)
    std::cout << max_val("hi", "hello") << "
"; // hello (string version)
    return 0;
}

Default Arguments

defaults.cpp
#include <iostream>

void log(const std::string& msg, const std::string& level = "INFO") {
    std::cout << "[" << level << "] " << msg << "
";
}

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

int main() {
    log("Server started");            // [INFO] Server started
    log("Connection failed", "ERROR"); // [ERROR] Connection failed

    std::cout << power(5) << "
";     // 25 (default exp=2)
    std::cout << power(2, 10) << "
"; // 1024
    return 0;
}

Lambda Expressions (C++11)

lambdas.cpp
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // Basic lambda
    auto add = [](int a, int b) { return a + b; };
    std::cout << add(3, 5) << "
";  // 8

    // Lambda with capture
    int multiplier = 3;
    auto times = [multiplier](int x) { return x * multiplier; };
    std::cout << times(7) << "
";  // 21

    // Lambda with algorithms
    std::vector<int> nums{5, 2, 8, 1, 9, 3};
    std::sort(nums.begin(), nums.end(), [](int a, int b) {
        return a > b;  // descending order
    });
    for (int n : nums) std::cout << n << " ";  // 9 8 5 3 2 1
    std::cout << "
";

    // Generic lambda (C++14)
    auto print = [](const auto& x) { std::cout << x << "
"; };
    print(42);
    print("hello");
    print(3.14);

    return 0;
}

Best Practices

  • Pass small types (int, double) by value and large types (string, vector, custom classes) by const&.
  • Use [[nodiscard]] on functions whose return value should not be ignored (C++17).
  • Declare functions before use — put prototypes in header files for multi-file projects.
  • Keep functions short and focused — each function should do one thing well.
  • Use lambdas for short, one-off operations passed to algorithms or callbacks.
  • Avoid output parameters — prefer returning values (use structured bindings for multiple returns).

Keep Practicing

Use the online compiler to run every example and experiment with modifications. The best way to learn C++ is by writing code — even small programs build strong foundations.