Introduction to C++
Understand what C++ is, how it differs from C, and why it powers games, trading systems, and operating systems.
What is C++?
C++ is a general-purpose, statically typed, compiled programming language created by Bjarne Stroustrup at Bell Labs in 1979. It was designed as an extension of C, adding object-oriented features while preserving C’s low-level memory control and raw performance.
Unlike managed languages such as Java or Python, C++ compiles directly to machine code. There is no virtual machine, no garbage collector, and no runtime overhead unless you explicitly introduce it. This makes C++ the language of choice wherever performance is non-negotiable: when 60 frames per second in a game engine, microsecond latency in a trading system, or megabytes of binary footprint in an embedded device are the constraints you must live within, C++ is where you turn.
C++ vs C: What Changed?
Understanding the differences between C and C++ matters because it explains why C++ exists and what problems it was created to solve. C is a powerful but spartan language: it gives you direct memory access and near-zero runtime overhead, but it provides almost no help managing complexity in large codebases. C++ keeps everything C offers and layers on features that make large-scale software manageable and safer.
| Feature | C | C++ |
|---|---|---|
| Classes & structs with methods | No | Yes |
| RAII (automatic resource cleanup) | No | Yes |
| Templates (generic programming) | No | Yes |
| Standard Template Library (STL) | No | Yes |
| Exceptions | No | Yes |
| References | No | Yes |
| Function/operator overloading | No | Yes |
nullptr | No | Yes (C++11) |
The most important conceptual shift is RAII — Resource Acquisition Is Initialization. In C, you malloc memory and must remember to free it. Forget, and you leak. In C++, a destructor runs automatically when an object goes out of scope, guaranteeing cleanup regardless of how you exit a function — including when exceptions are thrown.
// C-style: manual, error-prone
FILE* f = fopen("data.txt", "r");
// ... if you forget fclose(f), you leak the file handle
// ... if an error occurs and you return early, you still leak
// C++ RAII: automatic cleanup
#include <fstream>
{
std::ifstream f("data.txt"); // opens file
// ... read data
} // destructor runs here, file is closed automatically — always
Your First C++ Program
Every C++ program starts with main(). The #include directives pull in standard library headers, and std::cout writes to standard output. The std:: prefix means these names live in the standard namespace, which keeps them from colliding with your own identifiers.
#include <iostream>
#include <string>
int main() {
std::string name = "World";
std::cout << "Hello, " << name << "!\n";
return 0;
}
Compile and run:
g++ -std=c++17 -o hello hello.cpp
./hello
# Hello, World!
Classes vs Structs
In C, a struct is just a bag of data. In C++, both struct and class can have methods, constructors, and destructors. The only difference is default access: struct members are public by default, class members are private. This distinction matters because it shapes how you communicate intent: use struct when a type is a transparent data holder, and class when you need to enforce invariants through encapsulation.
#include <iostream>
#include <string>
// struct: default public — good for plain data holders
struct Point {
double x;
double y;
double distance_from_origin() const {
return std::sqrt(x * x + y * y);
}
};
// class: default private — good for encapsulated objects with invariants
class BankAccount {
public:
BankAccount(std::string owner, double initial_balance)
: owner_(std::move(owner)), balance_(initial_balance) {}
void deposit(double amount) {
if (amount > 0) balance_ += amount; // enforce: no negative deposits
}
bool withdraw(double amount) {
if (amount > balance_) return false; // enforce: no overdraft
balance_ -= amount;
return true;
}
double balance() const { return balance_; }
private:
std::string owner_;
double balance_; // private: callers can't corrupt the invariant
};
int main() {
Point p{3.0, 4.0};
std::cout << "Distance: " << p.distance_from_origin() << "\n"; // 5
BankAccount acct("Alice", 1000.0);
acct.deposit(500.0);
acct.withdraw(200.0);
std::cout << "Balance: " << acct.balance() << "\n"; // 1300
}
Where C++ Is Used
C++ fills a specific niche: it is the tool you reach for when you need the full power of the hardware and cannot accept the overhead of a runtime or garbage collector.
Game Engines: Unreal Engine is written in C++. Games need to process physics, AI, rendering, and audio in 16 milliseconds per frame (60 fps). No managed language can deliver this reliably at scale.
High-Frequency Trading: HFT firms measure latency in microseconds. A single garbage collection pause would cost millions. C++ gives deterministic execution with no GC interruptions.
Browsers: Chrome’s V8 JavaScript engine, the rendering engine Blink, and Firefox’s Gecko are all written in C++. They parse HTML, execute JavaScript, and paint pixels — all in milliseconds.
Operating Systems: Linux kernel modules, Windows drivers, and macOS system libraries use C and C++. The kernel itself is C, but surrounding system software (like parts of Android’s ART runtime) is C++.
Embedded Systems: Microcontrollers in cars, medical devices, and industrial equipment run C++ because the binary footprint is small and there is no OS overhead.
The C++ Standards Timeline
C++ has evolved dramatically through ISO standardization. Each revision is identified by year. Knowing which standard your compiler targets — and which features it unlocks — is practical knowledge every C++ developer needs.
C++98/03 — the original standard. Introduced STL, templates, exceptions, namespaces.
C++11 — the modern C++ turning point. Added auto, nullptr, range-based for, std::thread, lambda expressions, std::unique_ptr/std::shared_ptr, move semantics, constexpr, static_assert.
C++14 — refinements. Generic lambdas, relaxed constexpr, std::make_unique.
C++17 — practical additions. Structured bindings (auto [key, val] = ...), if constexpr, std::optional, std::variant, std::filesystem, parallel algorithms.
C++20 — the biggest leap since C++11. Concepts (constraints on templates), Ranges, Coroutines, std::format, Modules, std::span, <=> spaceship operator.
C++23 — continued refinement. std::expected, std::print, std::mdspan, improvements to Ranges and Modules.
// Taste of modern C++20 — expressive, safe, still zero-overhead
#include <format>
#include <iostream>
#include <vector>
#include <ranges>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Ranges + views: lazy, composable pipelines — no intermediate allocations
auto even_squares = nums
| std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return n * n; });
for (int v : even_squares) {
std::cout << std::format("{} ", v); // 4 16 36 64 100
}
std::cout << "\n";
}
The key takeaway: modern C++ (C++17 and later) looks and feels quite different from 1990s C++. You write less boilerplate, make fewer mistakes, and still get the same raw performance.