Back to blog
Backend Systemsbeginner

C++ Basics & OOP

Learn C++ fundamentals: classes, constructors, destructors, access specifiers, operator overloading, and how C++ improves on C.

Asma HafeezApril 17, 20265 min read
cppoopclassesconstructorsc-plus-plus
Share:𝕏

C++ Basics & OOP

C++ extends C with classes, RAII, templates, and the STL. It's used for game engines, compilers, trading systems, and anywhere performance matters alongside abstraction.


Hello World

CPP
#include <iostream>   // std::cout, std::cin
#include <string>     // std::string

int main() {
    std::string name;
    std::cout << "Enter your name: ";
    std::cin >> name;
    std::cout << "Hello, " << name << "!\n";
    return 0;
}
Bash
g++ -std=c++20 hello.cpp -o hello
./hello

using namespace std

CPP
#include <iostream>
using namespace std;  // avoid typing std:: everywhere

int main() {
    cout << "Hello!\n";  // no std:: needed
}

References — C++'s Alternative to Pointers

CPP
int x = 10;
int& ref = x;   // ref is an alias for x

ref = 20;       // modifies x directly
cout << x;      // 20

// Pass by reference — modifies the original
void double_it(int& n) {
    n *= 2;
}

int val = 5;
double_it(val);
cout << val;    // 10

// Const reference — read-only access without copying
void print(const std::string& s) {
    cout << s << "\n";  // efficient — no copy
}

Classes

CPP
#include <iostream>
#include <string>

class Person {
private:                    // only accessible inside the class
    std::string name_;
    int age_;

public:                     // accessible from anywhere
    // Constructor
    Person(const std::string& name, int age)
        : name_(name), age_(age) {}  // initializer list — preferred

    // Getters
    const std::string& name() const { return name_; }
    int age() const { return age_; }

    // Method
    void greet() const {
        std::cout << "Hi, I'm " << name_ << ", age " << age_ << "\n";
    }

    // toString equivalent
    std::string toString() const {
        return "Person(" + name_ + ", " + std::to_string(age_) + ")";
    }
};

Person alice("Alice", 30);
alice.greet();                         // Hi, I'm Alice, age 30
std::cout << alice.name() << "\n";     // Alice
std::cout << alice.toString() << "\n"; // Person(Alice, 30)

Constructors and Destructors

CPP
class Buffer {
private:
    int* data_;
    int  size_;

public:
    // Constructor — allocates resource
    explicit Buffer(int size)
        : size_(size), data_(new int[size]) {
        std::cout << "Buffer created, size " << size << "\n";
    }

    // Destructor — automatically called when object goes out of scope
    ~Buffer() {
        delete[] data_;  // free heap memory
        std::cout << "Buffer destroyed\n";
    }

    // Copy constructor — deep copy
    Buffer(const Buffer& other)
        : size_(other.size_), data_(new int[other.size_]) {
        std::copy(other.data_, other.data_ + size_, data_);
    }

    // Copy assignment
    Buffer& operator=(const Buffer& other) {
        if (this == &other) return *this;  // self-assignment check
        delete[] data_;
        size_ = other.size_;
        data_ = new int[size_];
        std::copy(other.data_, other.data_ + size_, data_);
        return *this;
    }

    int size() const { return size_; }
    int& operator[](int i) { return data_[i]; }
};

{
    Buffer buf(5);          // Constructor called
    buf[0] = 10;
    buf[1] = 20;
}                           // Destructor called automatically — no free() needed!

RAII — Resource Acquisition Is Initialization

RAII is the C++ idiom where resources are tied to object lifetime.

CPP
// RAII file wrapper
class File {
    FILE* handle_;
public:
    explicit File(const char* path, const char* mode)
        : handle_(fopen(path, mode)) {
        if (!handle_) throw std::runtime_error("Cannot open file");
    }

    ~File() {
        if (handle_) fclose(handle_);  // always closed, even on exception
    }

    // Disable copy
    File(const File&) = delete;
    File& operator=(const File&) = delete;

    void writeLine(const std::string& line) {
        fprintf(handle_, "%s\n", line.c_str());
    }
};

try {
    File f("output.txt", "w");
    f.writeLine("Hello from RAII");
}  // f.~File() called here — file closed automatically

Inheritance

CPP
class Animal {
protected:
    std::string name_;

public:
    Animal(const std::string& name) : name_(name) {}

    virtual void speak() const {  // virtual — allows overriding
        std::cout << name_ << " makes a sound\n";
    }

    virtual ~Animal() = default;  // virtual destructor — essential for polymorphism
};

class Dog : public Animal {
public:
    Dog(const std::string& name) : Animal(name) {}

    void speak() const override {  // override — compile-time check
        std::cout << name_ << " barks: WOOF!\n";
    }

    void fetch() const {
        std::cout << name_ << " fetches the ball!\n";
    }
};

class Cat : public Animal {
public:
    Cat(const std::string& name) : Animal(name) {}

    void speak() const override {
        std::cout << name_ << " meows\n";
    }
};

// Polymorphism via base class pointer
std::vector<std::unique_ptr<Animal>> animals;
animals.push_back(std::make_unique<Dog>("Rex"));
animals.push_back(std::make_unique<Cat>("Whiskers"));

for (const auto& a : animals) {
    a->speak();  // polymorphic dispatch
}

Operator Overloading

CPP
class Vector2D {
public:
    double x, y;

    Vector2D(double x = 0, double y = 0) : x(x), y(y) {}

    // +, -, * operators
    Vector2D operator+(const Vector2D& other) const {
        return {x + other.x, y + other.y};
    }

    Vector2D operator*(double scalar) const {
        return {x * scalar, y * scalar};
    }

    bool operator==(const Vector2D& other) const {
        return x == other.x && y == other.y;
    }

    double length() const {
        return std::sqrt(x * x + y * y);
    }

    // Stream output
    friend std::ostream& operator<<(std::ostream& os, const Vector2D& v) {
        return os << "(" << v.x << ", " << v.y << ")";
    }
};

Vector2D a{3, 4}, b{1, 2};
Vector2D c = a + b;
std::cout << c << "\n";        // (4, 6)
std::cout << a.length() << "\n"; // 5.0

Structs in C++

In C++, struct and class are nearly identical — the only difference is default access (public for struct, private for class).

CPP
struct Point {
    double x, y;

    // Methods are fine in structs
    double distanceTo(const Point& other) const {
        double dx = x - other.x, dy = y - other.y;
        return std::sqrt(dx*dx + dy*dy);
    }
};

Point p1{0, 0}, p2{3, 4};
std::cout << p1.distanceTo(p2);  // 5.0

Key Takeaways

  1. Use references instead of pointers when the value can't be null
  2. RAII — tie resource lifetime to object lifetime; destructors handle cleanup
  3. Mark methods const when they don't modify the object — enables use on const objects
  4. Use virtual for methods you want subclasses to override; always add virtual ~ destructor
  5. override keyword catches typos — use it on every overridden method

Enjoyed this article?

Explore the Backend Systems learning path for more.

Found this helpful?

Share:𝕏

Leave a comment

Have a question, correction, or just found this helpful? Leave a note below.