BACKEND 101

Inter
C++

& Basic Java

A technical primer covering memory management, object-oriented design, the STL, and Java's JVM model — from pointers to polymorphism.

C++
Java
AGENDA

What
We Cover

30 slides · 2 parts

01–02

Intro & Agenda

Goals & overview

03–07

C++ Memory

Stack, heap, smart pointers

08–12

C++ OOP

Classes, inheritance, vtable

13–15

STL & Templates

Containers, algorithms

16–18

Modern C++

Lambdas, move, exceptions

19–25

Java OOP & Types

JVM, interfaces, generics

26–28

Java Modern

Streams, lambdas, exceptions

29–30

C++ vs Java

Comparison & takeaways

PART 01

Intermediate
C++

Memory  ·  OOP  ·  STL  ·  Modern Features

C++
SLIDES 04 – 18
INTERMEDIATE C++ · MEMORY
01

Stack vs Heap

Stack
AUTOAutomatic lifetime — cleaned up when scope exits
FASTLIFO allocation — just moves stack pointer
SIZEFixed at compile time; limited memory
USELocal variables, function parameters
Heap
MANUALAllocate with new, free with delete
FLEXArbitrary size, runtime-determined
RISKLeaks if not freed; fragmentation
USEDynamic objects, large data, shared data
int x = 5; // stack int* p = new int(5); // heap delete p; // manual free stack overflow risk on deep recursion
INTERMEDIATE C++ · MEMORY
02

Raw Pointers

Declaration & Initialization

A pointer stores a memory address. Declare with *, dereference with * to get the value, use & to get an address.

Pointer Arithmetic

Adding 1 to a pointer advances it by sizeof(T) bytes. Useful for traversing arrays but dangerous if out-of-bounds.

Dangling & Null Pointers

A dangling pointer points to freed memory — undefined behaviour. Always set to nullptr after deleting.

Common Pitfalls

Double-free, memory leak, buffer overflow. Raw pointers require strict discipline — prefer smart pointers instead.

C++ // Basic pointer usage int val = 42; int* ptr = &val; // address of val *ptr = 100; // dereference to write // Heap allocation int* arr = new int[5]; for (int i = 0; i < 5; ++i) arr[i] = i * 2; delete[] arr; // free array arr = nullptr; // avoid dangling // Pointer arithmetic int* p2 = arr + 2; // 3rd element *(p2 + 1) = 99; // 4th element
INTERMEDIATE C++ · MEMORY
03

Smart Pointers
unique_ptr

Sole Ownership

Only one unique_ptr can own a resource at a time. Cannot be copied — only moved.

Automatic Cleanup

The destructor calls delete automatically when the pointer goes out of scope. Zero overhead vs raw pointer.

make_unique

Preferred factory function. Exception-safe and avoids redundant type names. Available from C++14.

Transfer Ownership

Use std::move() to transfer ownership. The original pointer becomes nullptr after the move.

C++ #include <memory> // Create — preferred auto p = make_unique<int>(42); *p = 100; // use normally // deleted automatically at scope end // Custom class auto dog = make_unique<Dog>("Rex"); dog->bark(); // Transfer ownership auto p2 = std::move(p); // p is now nullptr // Get raw pointer if needed int* raw = p2.get();
INTERMEDIATE C++ · MEMORY
04

Smart Pointers
shared & weak

shared_ptr — Reference Counting

Multiple shared_ptrs share one resource. An internal counter tracks how many owners exist. Freed when count hits 0.

Circular Reference Problem

If A owns B and B owns A via shared_ptr, the count never reaches 0 — memory leaks permanently.

weak_ptr — Non-Owning Observer

Holds a reference without incrementing the count. Must be locked to access — safely detects expired pointers.

Use Pattern

Use shared_ptr for the primary owner; weak_ptr for observers or back-references to break cycles.

C++ // shared_ptr — ref counted auto s1 = make_shared<string>("hello"); auto s2 = s1; // ref count = 2 // use_count() == 2 // weak_ptr — non-owning weak_ptr<string> w = s1; // ref count still 2 // Must lock to use safely if (auto locked = w.lock()) { cout << *locked << endl; } s1.reset(); s2.reset(); // count = 0, memory freed // w.expired() == true
INTERMEDIATE C++ · OOP
05

Encapsulation
& Classes

Access Specifiers

private — class only  |  protected — class + derived  |  public — everyone

Constructors & Destructors

Constructor initialises the object; destructor cleans up. Use initialiser lists for efficiency: Dog(string n) : name(n) {}

The Rule of Three / Five / Zero

If you define a destructor, copy constructor, or copy-assignment, you likely need all three. With move semantics: the Rule of Five.

const Member Functions

Mark a method const to promise it won't modify the object. Allows calling on const references.

C++ class Dog { private: string name; int age; public: // Initialiser list constructor Dog(string n, int a) : name(n), age(a) {} // const getter string getName() const { return name; } void bark() { cout << "Woof!"; } }; // destructor auto-generated
INTERMEDIATE C++ · OOP
06

Inheritance

Public Inheritance

class Lab : public Dog — the derived class IS-A Dog. Public and protected members are inherited as-is.

Multiple Inheritance

C++ allows a class to inherit from multiple bases: class Amphibian : public Land, public Water. Risk: the Diamond Problem.

Virtual Base Classes

Use virtual on the shared base to avoid diamond duplication. Ensures only one copy of the base is inherited.

Calling Base Constructor

In the derived initialiser list: Lab(string n) : Dog(n, 1) {} — explicitly chains to the base constructor.

C++ class Animal { protected: string name; public: Animal(string n) : name(n) {} virtual void speak() = 0; }; class Dog : public Animal { public: Dog(string n) : Animal(n) {} void speak() override { cout << name << ": Woof!"; } }; Animal* a = new Dog("Rex"); a->speak(); // "Rex: Woof!"
INTERMEDIATE C++ · OOP
07

Polymorphism & Virtual

virtual

Declares a method as overridable. The compiler builds a vtable so the right version is called at runtime.

virtual void speak();

override

Compiler-verified re-implementation. Catches signature mismatches at compile time — prevents silent bugs.

void speak() override;

Pure Virtual

= 0 makes a method abstract. The class cannot be instantiated; derived classes must provide an implementation.

virtual void area() = 0;

vtable

A hidden lookup table built per class. A virtual call dereferences the vtable at runtime — tiny overhead, great flexibility.

ptr→vtable[i]();
INTERMEDIATE C++ · OOP
08

Abstraction &
Interfaces

Abstract Base Class

A class with at least one pure virtual method. Defines a contract — derived classes must implement all pure virtuals before they can be instantiated.

Interface Pattern

A fully abstract class (all methods pure virtual, no data) mimics Java/C# interfaces. Commonly used for DI and plugin patterns.

Virtual Destructor

Always declare base class destructors virtual. Otherwise deleting a derived object through a base pointer causes undefined behaviour (memory leak).

C++ // Interface pattern class IShape { public: virtual double area() = 0; virtual double perimeter() = 0; virtual ~IShape() = default; }; class Circle : public IShape { double r; public: Circle(double r) : r(r) {} double area() override { return 3.14159 * r * r; } double perimeter() override { return 2 * 3.14159 * r; } };
INTERMEDIATE C++ · OOP
09

Copy Control — Rule of Five

Copy Constructor

Called when initialising from another object. Default does shallow copy — override for deep copy when owning heap resources.

Dog(const Dog& other);

Copy Assignment

Called when assigning from another object. Must handle self-assignment and free old resources before copying.

Dog& operator=(const Dog& o);

Move Constructor

Transfers resources from a temporary (rvalue). Avoids deep copy — just steal the pointer and null the source.

Dog(Dog&& other) noexcept;

Move Assignment

Same idea as move constructor but for assignment. Free existing resources, steal from source, null the source.

Dog& operator=(Dog&& o) noexcept;
= default — compiler generates it = delete — prevents copying Rule of Zero — prefer smart pointers, no manual copies needed
INTERMEDIATE C++ · STL
10

STL Containers

ContainerAccessInsert / EraseOrderedBest Use Case
vector<T>O(1)O(1) amort. end / O(n) middleN/ADefault sequence; cache-friendly
deque<T>O(1)O(1) both endsN/AQueue-like access at front & back
list<T>O(n)O(1) anywhereN/AFrequent mid-sequence insert/erase
map<K,V>O(log n)O(log n)Yes (BST)Sorted key–value; range iteration
unordered_map<K,V>O(1) avgO(1) avgNo (hash)Fastest key–value lookups
set<T>O(log n)O(log n)YesUnique sorted elements
priority_queue<T>O(1) topO(log n)HeapAlways-max (or min) at top
prefer vector unless you have a specific reason unordered_map ~3× faster than map for lookups list = poor cache locality
INTERMEDIATE C++ · STL
11

STL Algorithms
& Iterators

Searching

find, find_if, count, binary_search, lower_bound, upper_bound

Sorting

sort, stable_sort, partial_sort, nth_element — all accept custom comparators

Transforming

transform, for_each, copy, copy_if, fill, replace, remove_if

Aggregating

accumulate, reduce, inner_product, min_element, max_element

C++ #include <algorithm> #include <numeric> vector<int> v = {3,1,4,1,5,9}; sort(v.begin(), v.end()); // {1, 1, 3, 4, 5, 9} auto it = find(v.begin(),v.end(),4); int sum = accumulate( v.begin(), v.end(), 0); transform(v.begin(), v.end(), v.begin(), [](int x){ return x*2; }); auto end = remove_if(v.begin(), v.end(), [](int x){ return x < 4; });
INTERMEDIATE C++ · TEMPLATES
12

Templates

Function Templates

Write one algorithm that works for any type. The compiler generates specialised versions at compile time — zero runtime overhead.

Class Templates

Parameterise an entire class by type(s). Foundation of every STL container. Type checking happens at compile time.

Template Specialisation

Provide a custom implementation for a specific type when the generic version isn't optimal: template<> class Stack<bool>

Variadic Templates (C++11)

Accept an arbitrary number of type parameters via typename... Args. Foundation of std::tuple and perfect forwarding.

C++ // Function template template<typename T> T maxVal(T a, T b) { return a > b ? a : b; } maxVal(3, 7); // T=int maxVal(3.14, 2.7); // T=double // Class template template<typename T> class Stack { vector<T> data; public: void push(T val) { data.push_back(val); } T top() { return data.back(); } void pop() { data.pop_back(); } }; Stack<string> s; s.push("hi");
INTERMEDIATE C++ · MODERN C++11+
13

Lambda
Expressions

C++11 auto & closures

Syntax

[capture](params) { body }[=] capture all by value, [&] by reference, or name specific variables.

Stored in auto / std::function

Assign to auto for zero-overhead; use std::function<R(Args)> when you need type-erasure or runtime polymorphism.

Perfect for Algorithms

Pass inline to sort, find_if, transform etc. Cleaner than writing separate functor classes for every comparator.

C++11 // Basic lambda auto greet = [](string name) { cout << "Hello, " << name; }; greet("World"); // Capture by reference int factor = 3; auto multiply = [&factor](int x) { return x * factor; }; // With STL algorithm vector<int> v = {5,2,8,1}; sort(v.begin(), v.end(), [](int a, int b){ return a > b; }); // descending: {8, 5, 2, 1}
INTERMEDIATE C++ · MODERN C++11+
14

Move Semantics
& Rvalue Refs

lvalue vs rvalue

An lvalue has a name / address (persists). An rvalue is temporary — a literal, a returned value. && binds to rvalues.

Why It Matters

Instead of copying a 1 GB buffer, a move constructor steals the pointer in O(1). Huge performance win for containers and strings.

std::move

Casts an lvalue to rvalue — tells the compiler "I no longer need the original." The moved-from object is in a valid but unspecified state.

Perfect Forwarding

std::forward<T> preserves value category through template functions — critical for generic factory patterns.

C++11 class Buffer { int* data; size_t sz; public: // Move constructor Buffer(Buffer&& other) noexcept : data(other.data), sz(other.sz) { other.data = nullptr; other.sz = 0; } }; Buffer a(1024); Buffer b = std::move(a); // 'a' is now empty (O(1) transfer) // Enables efficient container ops vector<Buffer> vec; vec.push_back(std::move(b));
INTERMEDIATE C++ · MODERN C++11+
15

Exception
Handling

try / catch / throw

Throw any type (prefer standard exceptions). Catch by const& to avoid slicing. Catch-all: catch (...)

Standard Exceptions

std::runtime_error, std::logic_error, std::out_of_range, std::bad_alloc — all derive from std::exception.

noexcept

Promise a function won't throw. Enables compiler optimisations and is required for move operations to be used in containers.

RAII over finally

C++ has no finally. Use RAII — destructors run even if an exception unwinds the stack. Smart pointers and lock_guard exploit this.

C++ #include <stdexcept> double divide(double a, double b) { if (b == 0.0) throw runtime_error("div by zero"); return a / b; } try { double r = divide(10, 0); } catch (const runtime_error& e) { cerr << "Error: " << e.what(); } catch (...) { cerr << "Unknown error"; } // RAII handles cleanup automatically
PART 02

Basic Java

JVM  ·  OOP  ·  Collections  ·  Streams

Java
SLIDES 20 – 28
BASIC JAVA · JVM
01

JVM Architecture

Java Source (.java) javac compiler
Bytecode (.class) platform-independent
JVM Classloader verify + load
JIT Compiler hot paths → native machine code

Write Once, Run Anywhere

Bytecode is OS-agnostic. Any machine with a JVM can run the same .class file — Windows, Linux, macOS, Android.

Garbage Collector

The GC automatically reclaims heap memory. Common algorithms: G1GC (default), ZGC, Shenandoah. No manual delete needed.

JIT Compilation

The JVM profiles at runtime and compiles frequently-executed (hot) methods to native code. Long-running Java can approach C++ speed.

Memory Areas

Heap (objects), Stack (frames), Metaspace (class metadata), Code Cache (JIT output). Each has separate GC policies.

BASIC JAVA · FUNDAMENTALS
02

Types &
Syntax

Primitive Types

byte, short, int, long
float, double
boolean, char

Wrapper Classes

Integer, Long, Double, Boolean… Autoboxing converts automatically between primitive and wrapper.

String

Immutable reference type. String pool interns literals. Use StringBuilder for concatenation in loops.

var (Java 10+)

Local type inference — compiler infers the type from the initialiser. Only works for local variables.

Java public class TypesDemo { public static void main(String[] args) { int x = 42; long big = 9_000_000_000L; double pi = 3.14159; boolean ok = true; // Autoboxing Integer boxed = x; // int → Integer int unboxed = boxed; // Integer → int // Type inference var name = "Java"; // String var list = new ArrayList<String>(); } }
BASIC JAVA · OOP
03

Classes &
Objects

Everything is an Object

All classes inherit from Object. Methods like toString(), equals(), hashCode() are inherited and often overridden.

No Destructors

GC handles deallocation. Use try-with-resources and AutoCloseable for deterministic resource cleanup (files, sockets).

Access Modifiers

public · protected · package-private (default) · private. Default is stricter than C++.

static vs instance

static members belong to the class, not an instance. static methods can't access this.

Java public class Dog { private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } @Override public String toString() { return name + " (age " + age + ")"; } } Dog d = new Dog("Rex", 3); System.out.println(d); // Rex (age 3)
BASIC JAVA · OOP
04

Inheritance
& @Override

Single Class Inheritance

Java allows only one parent class (extends). This avoids the diamond problem but restricts reuse — compensated by interfaces.

super keyword

Call the parent constructor with super(args) as the first line. Access parent methods with super.methodName().

@Override annotation

Compile-time verification that you're actually overriding an inherited method. Prevents typo bugs that silently create a new method instead.

final class / method

final on a class prevents subclassing. final on a method prevents overriding. String is a final class.

Java abstract class Animal { protected String name; Animal(String n) { name = n; } abstract void speak(); } class Dog extends Animal { Dog(String n) { super(n); } @Override void speak() { System.out.println(name + ": Woof"); } } Animal a = new Dog("Rex"); a.speak(); // Rex: Woof
BASIC JAVA · OOP
05

Interfaces
& Abstract Classes

interface

Pure contract — all methods are public abstract by default. A class can implement multiple interfaces. No instance variables (only constants).

default methods (Java 8+)

Interfaces can have concrete default methods — allows adding behaviour to existing interfaces without breaking all implementors.

abstract class

Can have fields, constructors, concrete methods, and abstract methods. Used when you want partial implementation shared across subclasses.

When to use which?

Interface for capability contracts (Runnable, Comparable). Abstract class for shared state and template pattern inheritance.

Java interface Flyable { void fly(); default void land() { System.out.println("Landing..."); } } interface Swimmable { void swim(); } // Multiple interface impl class Duck extends Animal implements Flyable, Swimmable { @Override public void fly() { ... } @Override public void swim() { ... } @Override void speak() { ... } }
BASIC JAVA · COLLECTIONS
06

Java Collections Framework

InterfaceImpl ClassOrderedDuplicatesThread-Safe Alt
ListArrayListYes (insertion)YesCopyOnWriteArrayList
ListLinkedListYes (insertion)Yes
SetHashSetNoNoConcurrentSkipListSet
SetTreeSetSortedNo
MapHashMapNoKeys: NoConcurrentHashMap
MapTreeMapSorted by keyKeys: No
QueuePriorityQueueHeap orderYesPriorityBlockingQueue
ArrayList ≈ C++ vector HashMap ≈ C++ unordered_map TreeMap ≈ C++ map Collections.unmodifiableList() for read-only views
BASIC JAVA · GENERICS
07

Java Generics

Type Parameters

class Box<T> — T is a type placeholder. Replaced at compile time; enforces type safety without casts.

Bounded Type Parameters

<T extends Comparable<T>> — restricts T to types that implement Comparable. Enables calling .compareTo() inside the generic code.

Type Erasure

Generic type info is erased at runtime — the JVM only sees raw types. This differs from C++ templates which generate type-specific code.

Wildcards

List<?> — unknown type. List<? extends Number> — covariant (read-only). List<? super Integer> — contravariant (write).

Java // Generic class class Pair<A, B> { private final A first; private final B second; Pair(A a, B b) { first=a; second=b; } A getFirst() { return first; } B getSecond() { return second; } } // Generic method public static <T extends Comparable<T>> T max(T a, T b) { return a.compareTo(b) >= 0 ? a : b; } max(3, 7); // returns 7 max("apple","mango"); // "mango"
BASIC JAVA · STREAMS
08

Streams &
Lambdas

Java 8 functional style
Source
filter
map
sorted
Terminal

Intermediate Operations

Lazy — return a new Stream. Examples: filter, map, flatMap, distinct, sorted, limit, skip

Terminal Operations

Eager — trigger computation. Examples: collect, count, reduce, forEach, findFirst, anyMatch

Java 8 List<String> names = List.of( "Alice", "Bob", "Charlie", "Anna"); // Filter → map → collect List<String> result = names.stream() .filter(n -> n.startsWith("A")) .map(String::toUpperCase) .sorted() .collect(Collectors.toList()); // ["ALICE", "ANNA"] // Reduce int sum = IntStream.rangeClosed(1,100) .reduce(0, Integer::sum); // 5050 // Optional to avoid null Optional<String> first = names.stream().findFirst();
BASIC JAVA · EXCEPTIONS
09

Exception
Handling

Checked vs Unchecked

Checked (extends Exception) — must be declared or caught. Unchecked (extends RuntimeException) — optional. Error = JVM-level, unrecoverable.

try-with-resources

Resources implementing AutoCloseable are closed automatically. No finally block needed for cleanup — cleaner and exception-safe.

Multi-catch (Java 7+)

Catch multiple exception types in one block: catch (IOException | SQLException e). Reduces boilerplate.

Custom Exceptions

Extend Exception or RuntimeException. Add context via constructor. Prefer unchecked for unrecoverable programming errors.

Java // Custom exception class InsufficientFundsException extends RuntimeException { InsufficientFundsException(double amt) { super("Need: $" + amt); } } // try-with-resources try (BufferedReader br = new BufferedReader(new FileReader(f))) { String line = br.readLine(); } catch (IOException | ParseException e) { logger.error(e.getMessage()); } finally { // always runs (optional) }
KEY DIFFERENCES
COMPARE

C++ vs Java

C++
Java
Memory
Manual (new/delete) + smart pointers (RAII)
Automatic Garbage Collection — no manual free
Execution
Compiled directly to native machine code
Bytecode → JVM → JIT → near-native speed
Inheritance
Multiple class inheritance via virtual
Single class + unlimited interface implements
Templates / Generics
Templates — full code generation per type
Generics — type erasure at runtime
Performance
Highest — zero-cost abstractions, no GC pauses
Excellent — JIT reaches near-native, GC pauses exist
Portability
Compile per platform; conditional compilation
Write once, run anywhere on any JVM
KEY TAKEAWAYS

What You
Now Know

01

C++ gives direct memory control — smart pointers make it safe via RAII

02

OOP pillars (encapsulation, inheritance, polymorphism, abstraction) apply to both languages with different syntax

03

STL containers + algorithms + templates unlock powerful generic programming in C++

04

Modern C++ (lambdas, move semantics) eliminates most manual memory work

05

Java's JVM model prioritises portability, automatic memory, and runtime adaptability

06

Java interfaces + generics + streams enable clean, expressive backend architecture

C++
+
Java