Structs and Aggregates
Bundling related values into a single named type — the gateway to object-oriented programming.
Once your programs grow past a few variables, you'll find yourself
passing the same group of values around together: a point's x
and y, a person's name, age, email. C++ lets you give that
group a name — a struct — and then treat it as one thing.
A struct is a named bundle
struct Point {
double x;
double y;
};That's it. Point is now a type. You can create one, copy it,
return it, store it in a vector, anything you can do with a built-in
type.
In memory, a Point is just the two doubles laid out one after
the other:
The compiler may insert padding to align fields properly. Don't
worry about that yet — just know sizeof(Point) may be slightly
larger than the sum of its parts.
Initialization shapes
Point a; // default-initialized; fields are uninitialized!
Point b{}; // value-initialized; both fields zero
Point c{3.0, 4.0}; // aggregate init in declaration order
Point d{.x = 3.0, .y = 4.0}; // designated initializers (C++20)The third and fourth forms are the safest and most readable. Always explicitly initialize structs — uninitialized fields are a classic source of silent bugs.
Passing structs to functions
Structs follow the same value/reference rules as built-in types.
double length(const Point& p) { // const ref: no copy, can't modify
return std::sqrt(p.x * p.x + p.y * p.y);
}
void scale(Point& p, double k) { // non-const ref: modify caller
p.x *= k;
p.y *= k;
}
Point midpoint(Point a, Point b) { // by value: small struct, fine
return {(a.x + b.x) / 2.0, (a.y + b.y) / 2.0};
}Rule of thumb: pass by const& unless the struct is two or three
fundamental fields, in which case by value is fine and may even be
faster.
Aggregates of aggregates
Structs compose. A Rectangle can be made of two Points:
This is the seed of object-oriented design: small, focused types combined into larger ones.
std::pair and std::tuple
For one-off groupings where naming a struct would be overkill, the standard library provides:
For anything more than two or three values, or anything that will
appear in more than one function, define a real struct. It's far
more readable.
struct vs class
In C++, struct and class are almost the same. The only
language-level difference is the default access level:
structmembers arepublicby default.classmembers areprivateby default.
Conventionally:
- Use
structfor plain data bundles (no invariants, no methods, or trivial methods). - Use
classwhen you have invariants to protect (data that must always satisfy some condition) — which leads us straight into the object-oriented chapter.
Challenges
Given a hard-coded list of three Points in main, compute the centroid (average of x, average of y) and print it as x y with no extra formatting. Expected output: 3 4.
Test your understanding
In C++, what is the only language-level difference between struct and class?
struct cannot have methods.
class is allocated on the heap, struct on the stack.
The default member access: struct members are public by default, class members are private by default.
struct does not support inheritance.
Why is Point p; (default-initialized) potentially dangerous?
It allocates memory on the heap.
The fields hold whatever bytes were already in that memory, so reading them is undefined behavior until you assign meaningful values.
It is forbidden by the C++ standard.
It causes the compiler to emit a warning.
Next: the leap from passive data bundles to active objects with behaviour — classes.