logo

C++ - struct vs class vs union

In C++, struct, class, and union are user-defined types with distinct memory layouts, encapsulation rules, and idiomatic use cases.

struct vs class

Technically, in C++, a struct and a class are almost identical in capability—both support member functions, constructors, destructors, virtual methods, and templates.

The only two syntactic differences are defaults:

  1. Default Member Access:
    • struct: members and methods default to public.
    • class: members and methods default to private.
  2. Default Inheritance Access:
    • struct Derived : Base inherits public by default.
    • class Derived : Base inherits private by default.
struct Point {
    int x; // public by default
    int y; // public by default
};

class BankAccount {
    double balance; // private by default
public:
    void deposit(double amount) { balance += amount; }
};

Idiomatic Convention (Google C++ Style Guide)

  • Use struct for passive objects that carry data (Data Transfer Objects / Plain Old Data) with public members and no complex invariants.
  • Use class for objects with internal state, encapsulation, invariants, and private data controlled via public member functions.

union

A union is a special class type where all non-static data members share the same memory location. Its size is equal to the size of its largest member (plus any necessary alignment padding).

union DataValue {
    int int_val;
    float float_val;
    char char_val;
};

DataValue val;
val.int_val = 42;
val.float_val = 3.14f; // Overwrites int_val in memory

Key Union Characteristics:

  • Single Active Member: Only one member can be safely read at a time (the one most recently written). Reading an inactive member is undefined behavior (type-punning rules).
  • No Inheritance / Virtual Functions: A union cannot inherit or be inherited from, and cannot declare virtual methods.
  • Modern Alternative (std::variant): In C++17, use std::variant<int, float, std::string> instead of raw unions for type-safe, tagged union behavior with exception-safe construction/destruction of non-trivial types.

Comparison Summary

Feature struct class union
Default Member Access public private public
Default Inheritance public private Inheritance not permitted
Memory Layout Sequential (each member has own offset) Sequential (each member has own offset) Overlapping (shared base address)
Size Sum of members + padding Sum of members + padding Size of largest member (+ alignment)
Active Members All members active concurrently All members active concurrently Exactly one active member
Idiomatic Purpose Passive data holder (POD / DTO) Encapsulated business logic & invariants Low-level memory optimization / bit-level mapping
Modern Alternative std::variant (C++17)