cv.cm

Coding · Programming languages

C++ tutorial for beginners

7 min read

Short answer

C++ is a compiled, statically typed language that combines the speed and low-level control of C with classes, templates and a large standard library. Compile hello.cpp with g++ -std=c++20 hello.cpp -o hello and run ./hello. Modern C++ code uses std::string, std::vector and std::map instead of raw arrays, smart pointers instead of manual delete, and RAII so that resources are released automatically.

Open Binary converter

What C++ is and what it is used for

C++ was created by Bjarne Stroustrup at Bell Labs, starting in 1979 as "C with Classes". It is standardized by ISO; C++11 began the "modern C++" era, and C++17, C++20 and C++23 followed. C++ is used where performance and control matter: game engines (Unreal Engine), web browsers (Chrome, Firefox), databases, trading systems, embedded devices, compilers and machine-learning runtimes. Its guiding idea is zero-overhead abstraction: features you do not use cost nothing.

Install a compiler and run Hello, world

Use GCC (g++) or Clang (clang++) on Linux and macOS, or Microsoft Visual C++ on Windows (via Visual Studio). Pick a standard version explicitly.

#include <iostream>

int main() {
    std::cout << "Hello, world\n";
    return 0;
}
g++ -std=c++20 -Wall -Wextra hello.cpp -o hello
./hello
# Hello, world

std::cout is the standard output stream and << writes to it. Everything in the standard library lives in the namespace std.

Variables, types and auto

C++ has the same built-in types as C, plus bool as a keyword, references, and library types such as std::string. auto asks the compiler to deduce the type from the initializer. Brace initialization {} refuses narrowing conversions.

TypeExampleNotes
int, long longint n{42};Signed integers
doubledouble x{3.14};64-bit floating point
boolbool ok{true};true or false
charchar c{'A'};One byte
std::stringstd::string s{"hi"};Growable text, from <string>
autoauto v = 2.5;Deduced, here double
T&int& r = n;A reference: another name for n
#include <iostream>
#include <string>

int main() {
    int count{7};
    auto avg = count / 2.0;          // double, 3.5
    std::string name{"Ada"};
    name += " Lovelace";
    const int& ref = count;          // read-only alias of count
    std::cout << name << " " << name.size() << " " << avg << " " << ref << "\n";
    // Ada Lovelace 12 3.5 7
}

Control flow and functions

Control flow is the same as in C, plus the range-based for loop. Pass large objects by const reference to avoid copies, and by non-const reference when the function should change them.

#include <iostream>
#include <string>
#include <vector>

int square(int x) { return x * x; }

void addSuffix(std::string& s, const std::string& suffix = "!") {
    s += suffix;
}

int main() {
    int score = 72;
    if (score >= 90) std::cout << "A\n";
    else if (score >= 70) std::cout << "B\n";   // B
    else std::cout << "C\n";

    std::vector<int> nums{1, 2, 3};
    for (int n : nums) std::cout << square(n) << " ";  // 1 4 9
    std::cout << "\n";

    std::string word = "hi";
    addSuffix(word);
    std::cout << word << "\n";                  // hi!
}

Classes

A class groups data members and member functions. Constructors set up an object; private members are hidden from outside code. A struct is the same as a class except that members are public by default.

#include <iostream>
#include <string>
#include <utility>

class Account {
public:
    explicit Account(std::string owner) : owner_(std::move(owner)) {}

    void deposit(double amount) {
        if (amount > 0) balance_ += amount;
    }
    double balance() const { return balance_; }
    const std::string& owner() const { return owner_; }

private:
    std::string owner_;
    double balance_ = 0.0;
};

int main() {
    Account acc{"Ann"};
    acc.deposit(50);
    acc.deposit(-5);   // ignored
    std::cout << acc.owner() << ": " << acc.balance() << "\n";  // Ann: 50
}

Inheritance (class Savings : public Account) and virtual functions give runtime polymorphism. Mark overriding functions with override so the compiler checks them.

Standard library containers and algorithms

The standard library (often called the STL) provides containers and algorithms that work together through iterators.

ContainerLikeUse it for
std::vector<T>Dynamic arrayThe default sequence container
std::array<T, N>Fixed arraySize known at compile time
std::map<K, V>Sorted dictionaryOrdered keys, O(log n) lookup
std::unordered_map<K, V>Hash tableFast average O(1) lookup
std::set<T>Sorted unique setMembership, ordered output
#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <vector>

int main() {
    std::vector<int> nums{3, 1, 2, 5};
    std::sort(nums.begin(), nums.end());
    auto evens = std::count_if(nums.begin(), nums.end(),
                               [](int n) { return n % 2 == 0; });
    std::cout << nums.front() << " " << nums.back() << " " << evens << "\n";  // 1 5 1

    std::map<std::string, int> ages{{"bob", 25}, {"ann", 31}};
    ages["cy"] = 40;
    for (const auto& [name, age] : ages) {     // structured bindings
        std::cout << name << "=" << age << " ";  // ann=31 bob=25 cy=40
    }
    std::cout << "\n";
}

[](int n) { ... } is a lambda, an unnamed function written inline. Templates are what make one std::vector work for any element type; you can write your own with template <typename T>.

Signature feature: RAII and smart pointers

RAII (Resource Acquisition Is Initialization) means a resource is owned by an object: the constructor acquires it and the destructor releases it. Because destructors run automatically when an object goes out of scope, even when an exception is thrown, memory, files and locks cannot leak. Smart pointers apply RAII to heap memory.

#include <iostream>
#include <memory>

struct Noisy {
    int id;
    explicit Noisy(int i) : id(i) { std::cout << "create " << id << "\n"; }
    ~Noisy() { std::cout << "destroy " << id << "\n"; }
};

int main() {
    auto a = std::make_unique<Noisy>(1);       // sole owner
    {
        auto b = std::make_shared<Noisy>(2);   // shared, reference-counted
        auto c = b;                            // two owners now
        std::cout << "owners: " << b.use_count() << "\n";
    }                                          // destroy 2 happens here
    std::cout << "end of main\n";
}                                              // destroy 1 happens here

Output: create 1, create 2, owners: 2, destroy 2, end of main, destroy 1. In modern code you should almost never write new and delete yourself.

Error handling with exceptions

Throw an exception object and catch it by const reference. Standard exception types are in <stdexcept>. Functions that never throw can be marked noexcept.

#include <iostream>
#include <stdexcept>
#include <string>

int parseAge(const std::string& text) {
    int age = std::stoi(text);   // throws std::invalid_argument on "abc"
    if (age < 0) throw std::out_of_range("negative age");
    return age;
}

int main() {
    try {
        std::cout << parseAge("41") << "\n";   // 41
        std::cout << parseAge("abc") << "\n";
    } catch (const std::invalid_argument&) {
        std::cout << "not a number\n";         // not a number
    } catch (const std::exception& e) {
        std::cout << "error: " << e.what() << "\n";
    }
}

For expected failures, many codebases return std::optional<T> (C++17) or std::expected<T, E> (C++23) instead of throwing.

A small complete program: word frequency

#include <algorithm>
#include <cctype>
#include <fstream>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>

int main(int argc, char* argv[]) {
    if (argc != 2) {
        std::cerr << "usage: " << argv[0] << " FILE\n";
        return 1;
    }
    std::ifstream in(argv[1]);
    if (!in) {
        std::cerr << "cannot open " << argv[1] << "\n";
        return 1;
    }
    std::unordered_map<std::string, int> counts;
    std::string word;
    while (in >> word) {
        std::string clean;
        for (unsigned char ch : word)
            if (std::isalpha(ch)) clean += static_cast<char>(std::tolower(ch));
        if (!clean.empty()) ++counts[clean];
    }
    std::vector<std::pair<std::string, int>> top(counts.begin(), counts.end());
    std::sort(top.begin(), top.end(),
              [](const auto& a, const auto& b) { return a.second > b.second; });
    for (size_t i = 0; i < top.size() && i < 5; ++i)
        std::cout << top[i].second << "  " << top[i].first << "\n";
}

Compile with g++ -std=c++20 -O2 words.cpp -o words and run ./words notes.txt. The file is closed automatically when in goes out of scope, which is RAII again.

Common beginner mistakes

  • Writing using namespace std; in header files, which pollutes every file that includes them.
  • Passing large objects such as std::vector by value when a const& would do.
  • Mixing signed and unsigned in comparisons, such as int i against v.size(). Enable warnings to see these.
  • Keeping an iterator or reference into a std::vector after push_back, which may move the elements.
  • Using raw new and delete instead of std::make_unique, std::vector or other owning types.

Where to go next

Use cppreference.com as the language and library reference, and the C++ Core Guidelines (edited by Bjarne Stroustrup and Herb Sutter) for good practice. The Standard C++ Foundation site isocpp.org has a getting-started page with recommended books. Learn CMake for building projects, then move on to move semantics, templates, constexpr and concurrency with std::thread.

FAQ

Should I learn C before C++?

It is not required. Modern C++ teaching starts with std::string, std::vector and classes, and introduces raw pointers and C-style arrays later. Learning C first does help you understand memory.

Which C++ standard should I use?

C++17 and C++20 are well supported by current GCC, Clang and MSVC, and C++23 support is growing. Choose one explicitly with a flag such as -std=c++20.

What is the difference between a pointer and a reference?

A reference is an alias that must be bound when created and cannot be reseated or be null. A pointer stores an address, can be null and can be changed to point elsewhere.

Is C++ hard to learn?

The language is large, so expect a longer learning curve than Python or Go. Sticking to modern features, standard containers and smart pointers avoids most of the classic pitfalls.

All coding tutorials