Curated questions covering OOP, STL, templates, memory management, virtual functions, smart pointers, and modern C++11/14/17/20 features.
C++ is a general-purpose language extending C with OOP, templates, exceptions, and the STL. Key additions over C: classes and objects, inheritance, polymorphism, encapsulation, function/operator overloading, references, templates, exceptions, and the Standard Template Library.
struct Point { int x, y; }; // public by default\nclass Circle { int radius; }; // private by defaultclass Animal {};\nclass Dog : public Animal {}; // is-a\nclass Engine {};\nclass Car : private Engine {}; // implemented-in-terms-ofA virtual function is declared with the virtual keyword in the base class. When called through a base class pointer/reference, the derived class version is called at runtime (dynamic dispatch via vtable).
class Shape {\npublic:\n virtual double area() const = 0; // pure virtual\n virtual ~Shape() {} // virtual destructor\n};\nclass Circle : public Shape {\n double r;\npublic:\n Circle(double r) : r(r) {}\n double area() const override { return 3.14 * r * r; }\n};\nShape* s = new Circle(5);\nprintf("%.2f", s->area()); // calls Circle::area()class Base {\npublic:\n virtual void foo() { cout << "Base"; } // virtual\n virtual void bar() = 0; // pure virtual\n};// Overloading\nvoid print(int x) {}\nvoid print(double x) {}\n\n// Overriding\nclass Base { virtual void show() { cout << "Base"; } };\nclass Derived : public Base { void show() override { cout << "Derived"; } };class MyClass {\npublic:\n MyClass() {} // default\n MyClass(int x) : val(x) {} // parameterized\n MyClass(const MyClass& o) : val(o.val) {} // copy\n MyClass(MyClass&& o) : val(o.val) { o.val = 0; } // move\nprivate:\n int val;\n};MyClass a(5);\nMyClass b = a; // copy constructor\nMyClass c;\nc = a; // assignment operatorA destructor (~ClassName) is called automatically when an object goes out of scope or is deleted. Used to release resources. Always declare destructors virtual in base classes to ensure proper cleanup of derived objects.
class Resource {\n int* data;\npublic:\n Resource() { data = new int[100]; }\n ~Resource() { delete[] data; } // cleanup\n};\n\nclass Base {\npublic:\n virtual ~Base() {} // virtual destructor - essential!int* p = new int(42); // calls constructor\ndelete p; // calls destructor\n\nint* arr = new int[10];\ndelete[] arr; // use delete[] for arraysSmart pointers automatically manage memory, preventing leaks. Defined in
auto up = make_unique<int>(42); // unique ownership\nauto sp = make_shared<int>(42); // shared ownership\nweak_ptr<int> wp = sp; // non-owning\n\n// No manual delete needed!auto u = make_unique<MyClass>();\n// auto u2 = u; // ERROR: cannot copy\nauto u2 = move(u); // OK: transfer ownership\n\nauto s1 = make_shared<MyClass>();\nauto s2 = s1; // OK: both own the objectRAII is a C++ idiom where resource acquisition (memory, file handles, locks) is tied to object lifetime. Resources are acquired in the constructor and released in the destructor. Smart pointers, std::fstream, and std::lock_guard all use RAII.
class FileHandle {\n FILE* fp;\npublic:\n FileHandle(const char* name) { fp = fopen(name, "r"); }\n ~FileHandle() { if (fp) fclose(fp); } // auto-cleanup\n};\n// File is automatically closed when FileHandle goes out of scopeThe Standard Template Library provides generic containers, algorithms, and iterators.
vector<int> v = {3,1,4,1,5};\nsort(v.begin(), v.end());\nauto it = find(v.begin(), v.end(), 4);\naccumulate(v.begin(), v.end(), 0); // sumvector<int> v = {1,2,3};\nv.push_back(4); // O(1) amortized\nv[2]; // O(1) random access\n\nlist<int> l = {1,2,3};\nauto it = l.begin();\nadvance(it, 1);\nl.insert(it, 99); // O(1) insertionmap<string,int> m; // sorted, O(log n)\nunordered_map<string,int> um; // hash, O(1) avg\nm["key"] = 1;\num["key"] = 1;Templates enable generic programming - writing code that works with any type. Function templates and class templates are instantiated by the compiler for each type used.
// Function template\ntemplate<typename T>\nT max(T a, T b) { return a > b ? a : b; }\n\nmax(3, 5); // T = int\nmax(3.14, 2.71); // T = double\n\n// Class template\ntemplate<typename T>\nclass Stack {\n vector<T> data;\npublic:\n void push(T val) { data.push_back(val); }\n T pop() { T v = data.back(); data.pop_back(); return v; }\n};Template specialization provides a custom implementation for a specific type, overriding the generic template.
template<typename T>\nvoid print(T val) { cout << val; } // generic\n\n// Specialization for bool\ntemplate<>\nvoid print<bool>(bool val) {\n cout << (val ? "true" : "false");\n}int x = 5;\nint& ref = x; // reference - must be initialized\nref = 10; // modifies x directly\n\nint* ptr = &x; // pointer\n*ptr = 10; // must dereferencevoid byValue(string s) {} // copies string\nvoid byConstRef(const string& s) {} // no copy, read-only\nvoid byRef(string& s) {} // no copy, can modifyMove semantics allow transferring resources from a temporary (rvalue) object instead of copying them. This avoids expensive deep copies. Use std::move() to cast to rvalue reference.
vector<int> v1 = {1,2,3,4,5};\nvector<int> v2 = move(v1); // v1 is now empty, no copy\n\n// Move constructor\nMyClass(MyClass&& other) noexcept\n : data(other.data) {\n other.data = nullptr; // transfer ownership\n}int x = 5; // x is lvalue, 5 is rvalue\nint& r = x; // lvalue reference\nint&& rr = 5; // rvalue reference\nint&& rr2 = move(x); // cast lvalue to rvalueLambdas are anonymous function objects. Syntax: [capture](params) -> return_type { body }.
auto add = [](int a, int b) { return a + b; };\ncout << add(3, 4); // 7\n\n// Capture by value and reference\nint x = 10;\nauto f1 = [x]() { return x; }; // capture by value\nauto f2 = [&x]() { x++; }; // capture by reference\nauto f3 = [=]() { return x; }; // capture all by value\nauto f4 = [&]() { x++; }; // capture all by reference\n\n// With STL\nvector<int> v = {3,1,4,1,5};\nsort(v.begin(), v.end(), [](int a, int b) { return a > b; });vector<int> v = {3,1,4,1,5,9};\nsort(v.begin(), v.end()); // ascending\nsort(v.begin(), v.end(), greater<int>()); // descending\nstable_sort(v.begin(), v.end()); // preserves equal orderstack<int> s;\ns.push(1); s.push(2);\ncout << s.top(); // 2 (LIFO)\n\nqueue<int> q;\nq.push(1); q.push(2);\ncout << q.front(); // 1 (FIFO)set<int> s = {3,1,4,1,5}; // {1,3,4,5} - no duplicates\nmultiset<int> ms = {3,1,4,1,5}; // {1,1,3,4,5} - duplicates OKvector<pair<int,string>> v;\nv.push_back({1, "hello"}); // creates temporary, then moves\nv.emplace_back(1, "hello"); // constructs in-place, no temporaryauto x = 42; // int\nauto v = vector<int>(); // vector<int>\n\nint a = 5;\ndecltype(a) b = 10; // int (same type as a)\ndecltype(a + 1.0) c; // doublevoid f(int x) { cout << "int"; }\nvoid f(int* p) { cout << "ptr"; }\n\nf(NULL); // ambiguous - might call f(int)\nf(nullptr); // unambiguous - calls f(int*)class Base { virtual void foo() {} };\nclass Derived : public Base {\n void foo() override {} // compile error if Base::foo not virtual\n};\nclass Leaf : public Derived {\n void foo() final {} // cannot be overridden further\n};Base* b = new Derived();\nDerived* d = dynamic_cast<Derived*>(b); // safe runtime cast\nif (d) { /* cast succeeded */ }string s = "Hello";\ns += " World"; // easy concatenation\ns.length(); // 11\ns.substr(0, 5); // "Hello"\ns.find("World"); // 6array<int, 5> arr = {1,2,3,4,5}; // fixed size\nvector<int> v = {1,2,3}; // dynamic\nv.push_back(4); // can growstd::optional
optional<string> findUser(int id) {\n if (id == 1) return "Alice";\n return nullopt; // no value\n}\n\nauto user = findUser(1);\nif (user.has_value()) {\n cout << user.value();\n}\ncout << user.value_or("Unknown");variant<int, string, double> v = 42;\nv = "hello";\ncout << get<string>(v); // "hello"\n\n// Type-safe visitor\nvisit([](auto& val) { cout << val; }, v);any a = 42;\na = string("hello");\ncout << any_cast<string>(a); // "hello"\n// any_cast<int>(a); // throws bad_any_castconst int x = 5; // may be runtime\nconstexpr int y = 5; // must be compile-time\n\nconstexpr int factorial(int n) {\n return n <= 1 ? 1 : n * factorial(n-1);\n}\nconstexpr int f5 = factorial(5); // computed at compile time// Thread\nthread t([]{ doWork(); });\nt.join();\n\n// Async\nauto future = async(launch::async, []{ return compute(); });\nint result = future.get(); // blocks until donemutex mtx;\n\n// Manual (risky)\nmtx.lock();\n// critical section\nmtx.unlock();\n\n// RAII (preferred)\n{\n lock_guard<mutex> lock(mtx);\n // critical section - auto-unlocked\n}std::string_view (C++17) is a non-owning, read-only view of a string. It does not copy the string data. Use it for function parameters that only need to read a string.
void print(string_view sv) { // no copy\n cout << sv;\n}\n\nstring s = "Hello";\nprint(s); // works\nprint("World"); // works - no allocation\nprint(s.substr(0,3)); // works - no copy// std::tie\nint a, b;\ntie(a, b) = make_pair(1, 2);\n\n// Structured bindings (C++17)\nauto [x, y] = make_pair(1, 2);\n\nmap<string,int> m;\nfor (auto& [key, val] : m) {\n cout << key << ": " << val;\n}std::span
void process(span<int> data) {\n for (int x : data) cout << x;\n}\n\nint arr[] = {1,2,3,4,5};\nprocess(arr); // works\n\nvector<int> v = {1,2,3};\nprocess(v); // works - no copystd::format (C++20) is a type-safe, extensible string formatting function. Unlike printf, it is type-safe (no format string mismatches), supports custom types, and returns a string.
// printf - not type-safe\nprintf("Hello %s, you are %d years old\n", name, age);\n\n// std::format (C++20) - type-safe\nstring s = format("Hello {}, you are {} years old", name, age);\ncout << format("{:.2f}", 3.14159); // "3.14"std::ranges (C++20) provides range-based versions of STL algorithms that work directly on containers without needing begin()/end() pairs. They also support views (lazy transformations) and pipelines.
vector<int> v = {3,1,4,1,5,9};\n\n// Traditional\nsort(v.begin(), v.end());\n\n// Ranges (C++20)\nranges::sort(v);\n\n// Views pipeline\nauto result = v | views::filter([](int x){ return x > 3; })\n | views::transform([](int x){ return x * 2; });Coroutines (C++20) are functions that can be suspended and resumed. They use co_await, co_yield, and co_return. Used for async programming, generators, and cooperative multitasking without threads.
// Generator coroutine\ngenerator<int> fibonacci() {\n int a = 0, b = 1;\n while (true) {\n co_yield a;\n tie(a, b) = make_pair(b, a + b);\n }\n}class MyArray {\n int* data;\n int size;\npublic:\n // Deep copy constructor\n MyArray(const MyArray& o) : size(o.size) {\n data = new int[size];\n copy(o.data, o.data + size, data);\n }\n};class Box {\n double width;\npublic:\n friend double getWidth(Box b) { return b.width; } // friend\n double getW() { return width; } // member\n};class Vector2D {\npublic:\n float x, y;\n Vector2D operator+(const Vector2D& o) const {\n return {x + o.x, y + o.y};\n }\n bool operator==(const Vector2D& o) const {\n return x == o.x && y == o.y;\n }\n};Explore 500+ free tutorials across 20+ languages and frameworks.