Essential C++ Core Concepts for Technical Interviews

Preprocessor Macros versus Compile-Time Constants

Preprocessor directives like #define perform raw text substitution during compilation preprocessing. They bypass type checking, lack scope boundaries, and can cause macro expansion side effects. Conversely, const variables are evaluated by the compiler with strict type safety. Macros duplicate literal code across translation units, while const objects typically resolve to a single memory address and support compile-time constant folding.

Storage Duration and Scope Modifiers

The static keyword alters linkage and lifetime:

  • File/Local Scope: Restricts visibility to the current compilation unit and guarantees zero-initialization for uninitialized variables. Local static objects retain their values between function invocations.
  • Class Scope: Static data members are shared across all class instances and require a separate out-of-class definition. Static member functions operate without a this pointer, meaning they cannot access non-static members or be declared const/virtual.

The const qualifier enforces immutability. At file scope, it restricts linkage similarly to static. Within classes, const data members must be initialized through the member initializer list. const member functions guarantee they will not modify the object's logical state (except mutable members) and cannot be called on const instances.

Array Identifiers versus Pointers

Both allow indexed access, but an array name represents a fixed address and decays into a raw pointer when passed to functions. Arrays lack increment/decrement operators, and sizeof returns the total array size only within its declaration scope. Key differences include contiguous allocation for arrays versus arbitrary memory targeting for pointers, and the risk of buffer overflows in arrays compared to memory leaks with improperly managed pointers.

Inheritance Specifiers: override and final

  • override: Explicitly declares that a function replaces a base class virtual method. The compiler validates signature matching, preventing accidental new method creation due to typos.
  • final: Applied to a class, it blocks further derivation. Applied to a virtual method, it prevents descendant classes from overriding it. Both trigger compilation errors on violation.
class Framework {
public:
    virtual void initialize() = 0;
};

class Plugin : public Framework {
public:
    void initialize() final override { /* setup logic */ }
};

Initialization Strategies

Direct initialization matches arguments directly to constructor parameters. Copy initialization creates a temporary object followed by a copy constructor invocation, though modern compilers typically elide this step via optimization.

std::vector<int> direct_list{1, 2, 3};
std::vector<int> copy_assigned = direct_list;
// Compiler optimizes to direct construction where possible.

Cross-Translation Linkage with extern

extern declares symbols defined elsewhere, enabling modular codebases. extern "C" disables C++ name mangling, ensuring compatibility with C libraries.

// config.hpp
extern int system_version;
extern "C" void log_system_status(const char* info);

// config.cpp
#include "config.hpp"
int system_version = 5;

Pointer Validity Issues

Uninitialized pointers contain garbage addresses (wild pointers), while pointers to freed memory become dangling pointers. Solutions include initializing to nullptr, nullifying after deallocation, and utilizing RAII-compliant smart pointers (std::unique_ptr, std::shared_ptr) to automate resource cleanup.

Function Binding Mechanisms

  • Overloading: Multiple functions share a name in the same scope but differ in parameter types or counts. Return type differences are insufficient for disambiguation.
  • Overriding: A derived class provides a new implementation for a base class virtual method, requiring identical signatures.
  • Hiding: A derived class declares a method with the same name as a base method but different parameters, or the base method is non-virtual, masking the parent implementation.

Object Lifecycle Management

Constructors establish object state; destructors release acquired resources. Compilers generate trivial defaults if none are provided. Member initializer lists outperform in-body assignments, especially for references, const members, and non-default base constructors.

class Sensor {
public:
    Sensor(uint16_t addr, bool active) 
        : address(addr), is_active(active) {}
    
    ~Sensor() { /* teardown */ }
private:
    uint16_t address;
    const bool is_active;
};

Initialization follows: virtual bases -> direct bases -> member objects -> current class. Destruction reverses this order.

Copy Semantics: Shallow vs Deep

Shallow copying duplicates pointers, causing multiple objects to reference identical heap memory, leading to double-free errors. Deep copying allocates independent storage and replicates the underlying data.

class DataBlock {
public:
    DataBlock(const DataBlock& source) {
        length = source.length;
        payload = new uint8_t[length];
        std::memcpy(payload, source.payload, length);
    }
    ~DataBlock() { delete[] payload; }
private:
    size_t length;
    uint8_t* payload;
};

Access Control and Inheritance

Access specifiers (public, protected, private) govern member visibility. Inheritance mode determines how base class members appear in derived classes. public inheritance preserves base visibility levels. The friend keyword grants external functions or classes access to private and protected members.

Mutability and Explicit Construction

  • mutable: Allows specific members to be modified inside const methods, useful for internal caching or synchronization primitives.
  • explicit: Blocks implicit constructor conversions, enforcing strict type safety and requiring direct initialization syntax.

Exception Handling

C++ separates error propagation using try-catch blocks. throw triggers stack unwinding until a matching catch handler is found. The standard library offers std::exception and specialized derivatives for structured error reporting.

Parameter Passing Strategies

  • Value: Copies arguments into stack storage. Safe but costly for large types.
  • Pointer: Passes addresses. Enables modification and avoids copies but requires null checks and manual management.
  • Reference: Aliases the original object with pointer-like efficiency but value-like syntax. Returning references to local variables causes undefined behavior.

String Abstraction

std::string encapsulates dynamic character buffers, managing length and capacity automatically. It handles reallocation and null-termination internally, preventing manual memory errors and buffer overflows inherent to raw char* arrays.

Type Casting Operators

C++ enforces explicit casting semantics:

  • static_cast: Compile-time type conversions (numeric types, hierarchy upcasts/downcasts). No runtime validation for invalid downcasts.
  • dynamic_cast: Runtime-checked polymorphic downcasting. Returns nullptr or throws on mismatch.
  • const_cast: Modifies const/volatile qualifiers. Undefined behavior if original data was truly constant.
  • reinterpret_cast: Low-level bitwise type conversion. Used for hardware interfaces and raw memory inspection.

Variable Storage Classes

Global variables occupy static memory initialized at startup. Local variables use stack frames, created on entry and destroyed on exit. static locals preserve state across calls. static globals restrict linkage to the defining source file.

Function Call Stack Mechanics

Function invocation pushes an activation record containing the return address, parameters, saved context, and local variables. Parameters are typically pushed right-to-left. Nested calls consume stack space downward. Stack overflow or misaligned frames cause immediate crashes.

Process Memory Layout

Executable memory is segmented:

  • Code/Text: Read-only instructions, shared across processes.
  • Data/BSS: Initialized and zero-initialized static/global data.
  • Stack: Automatic storage for local variables and function calls. Fast, contiguous, but limited in size.
  • Heap: Dynamic allocation via new/malloc. Flexible, managed manually or via smart pointers, prone to fragmentation. Allocation occurs at compile-time (static), scope-entry (stack), or runtime (heap). Modern practices favor stack allocation and RAII containers over raw heap manipulation.

Tags: C++ Memory Management object lifecycle Pointer Semantics Exception Handling

Posted on Tue, 01 Sep 2026 16:24:18 +0000 by Kia