C++ Essentials 2 (CPP102 / CPPE2): Classes, Polymorphism, Templates, and STL
The C++ Essentials 2 (CPP102 / CPPE2) domain tests class-based and generic C++: special member functions, construction/destruction order, inheritance and dynamic polymorphism, operator overloading, exceptions, templates, and core STL usage. Questions often present a small hierarchy or container operation and ask which function runs, which object is copied, or what remains valid afterward.
Class mechanics and special members
- Non-static data members initialize in declaration order, not in the order of the constructor initializer list.
- The compiler generates copy/move constructors, copy/move assignment, and a destructor when viable; a user-declared destructor or copy operation can suppress implicit move generation.
= default,= delete, andexplicitcontrol special-member generation and implicit conversions.- The rule of three/five/zero: if a class manages a resource, define or delete the operations consistently.
Inheritance and dynamic polymorphism
- A function is polymorphic only when called through a pointer or reference to a base and the function is
virtual. overridemakes an intended override a compile-time error if no matching base virtual exists;finalprevents further overriding.- Deleting a derived object through a base pointer requires a virtual destructor; otherwise the behavior is undefined.
- Passing a derived object by value to a base parameter slices it: only the base subobject is copied.
Templates and STL
- Class/function templates are instantiated on use; each distinct argument type produces a distinct specialization.
- STL containers own their elements; iterators are invalidated by operations such as
vector::push_backthat reallocate. - Algorithms take iterator ranges
[first, last); lambdas capture by value[=]or by reference[&].
Worked example
struct Base {
virtual ~Base() = default;
virtual int f() const { return 1; }
};
struct Derived : Base {
int f() const override { return 2; }
};
void call(const Base& b) { std::cout << b.f(); }
int main() {
Derived d;
call(d); // prints 2
Base b = d; // slices
std::cout << b.f(); // prints 1
}
call(d) binds a const Base& to the Derived object; f is virtual, so dispatch reaches Derived::f. Base b = d copies only the Base subobject, so the dynamic type is Base and f returns 1.
Traps that cost marks
- Expecting initializer-list order to set initialization order.
- Forgetting a virtual destructor before deleting through
Base*. - Slicing when passing by value.
- Using an iterator after a reallocating container operation.
- Letting an exception escape a destructor during stack unwinding (
std::terminate).