Structs (struct vs class)

Reviewed & published by Brayan K

Real data comes in clusters: a point has an x and a y, a student has a name and a score, an order has an item, quantity, and price. A struct lets you bundle those related values into one named type so you can pass them around as a single thing. By the end of this lesson you'll define structs, store them in vectors, give them member functions, and understand exactly how struct and class differ.

Part of the free C++ course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn

💡 Real-World Analogy

A struct is a form with labelled fields. A "Contact" form has lines for Name, Phone, and Email — three different bits of information that belong together on one sheet. You don't carry around three loose scraps of paper; you keep one form. In code, a Contact struct holds those fields together, so you can pass one Contact to a function instead of three separate arguments. A class is the same form, but locked in a drawer where you must go through a clerk (public methods) to read or change anything — that's encapsulation.

1. Defining and Using a Struct

You declare a struct with the struct keyword, a name, and a list of members (the fields). Create an instance, then read and write its members with the dot operator .. The tidiest way to set everything at once is aggregate initialization with braces, which fills the members in declaration order. Don't forget the semicolon after the closing brace of the struct definition.

#include <iostream>
#include <string>
using namespace std;

// A struct bundles related data under one name.
struct Point {
    double x;   // members are public by default in a struct
    double y;
};

int main() {
    // Aggregate (brace) initialization fills members in order:
    Point a{3.0, 4.0};

    // Access members with the dot operator:
    cout << "a = (" << a.x << ", " << a.y << ")" << endl; // a = (3, 4)

    // You can also set members one at a time:
    Point b;
    b.x = 1.0;
    b.y = 2.0;
    cout << "b = (" << b.x << ", " << b.y << ")" << endl; // b = (1, 2)
    return 0;
}

// ✅ Expected output:
//    a = (3, 4)
//    b = (1, 2)

Your turn. Fill in the brace initializer to create a Book with the members in order:

#include <iostream>
#include <string>
using namespace std;

// 🎯 YOUR TURN — finish the Book struct.
struct Book {
    string title;
    string author;
    int    pages;
};

int main() {
    // Create a Book using brace initialization, in member order:
    Book b = ___;     // 👉 {"Dune", "Herbert", 412}

    cout << b.title << " by " << b.author
         << " (" << b.pages << " pages)" << endl;
    // ✅ Expected:  Dune by Herbert (412 pages)
    return 0;
}

🧩 Reorder Challenge

These lines define a Point struct and use it. Put them in the correct order:

A. struct Point { int x; int y; };
B.     cout << p.x + p.y << endl;
C. int main() {
D.     Point p{3, 4};
E.     return 0;
F. }

Correct order: A → C → D → B → E → F

Define the Point type first, before main (A), open main (C), create a point (D), print x + y = 7 (B), then return 0; (E) and close the brace (F). The struct must be declared before it's used.

2. struct vs class

Here's the question every C++ beginner asks. The only language-level difference is the default access level: in a struct, members are public by default; in a class, they're private by default. Everything else — constructors, methods, inheritance — is identical. By convention, programmers use struct for simple bundles of mostly-public data and class for types that hide their internals behind public methods (encapsulation).

#include <iostream>
using namespace std;

// struct: members default to PUBLIC.
struct OpenBox {
    int value;        // public -> accessible from outside
};

// class: members default to PRIVATE.
class ClosedBox {
    int value;        // private -> hidden from outside
public:
    void set(int v) { value = v; }     // public accessor
    int  get() const { return value; }
};

int main() {
    OpenBox o;
    o.value = 42;                   // ✅ allowed: public by default
    cout << "open: " << o.value << endl;   // open: 42

    ClosedBox c;
    // c.value = 42;                // ❌ error: 'value' is private
    c.set(99);                      // ✅ go through the public method
    cout << "closed: " << c.get() << endl; // closed: 99
    return 0;
}

// ✅ Expected output:
//    open: 42
//    closed: 99

📊 struct vs class at a Glance

Aspectstructclass
Default member accesspublicprivate
Default inheritancepublicprivate
Can have methods?yesyes
Can have constructors?yesyes
Typical use (convention)plain data bundleencapsulated type

3. Structs With Behaviour

A struct isn't limited to data — it can carry constructors (to set up its members) and member functions (to compute things from them). A member function marked const promises not to modify the struct, which both documents intent and lets you call it on const objects. This is exactly where a struct starts to look like a class.

#include <iostream>
#include <string>
using namespace std;

// Structs can have constructors and member functions, just like classes.
struct Rectangle {
    double width;
    double height;

    // Constructor: runs when a Rectangle is created.
    Rectangle(double w, double h) : width(w), height(h) {}

    // A member function. 'const' means it won't modify the struct.
    double area() const { return width * height; }
    double perimeter() const { return 2 * (width + height); }
};

int main() {
    Rectangle r(4.0, 3.0);
    cout << "area: "      << r.area()      << endl;  // area: 12
    cout << "perimeter: " << r.perimeter() << endl;  // perimeter: 14
    return 0;
}

// ✅ Expected output:
//    area: 12
//    perimeter: 14

4. A Vector of Structs

The single most useful pattern in everyday C++ is a vector<Struct> — a table of records. Each element is one row (a student, an order, a point), and you can loop, filter, and sort them with a lambda comparator. This combines structs with the vectors, range-based loops, and lambdas you've already learned.

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

struct Student {
    string name;
    int    score;
};

int main() {
    // A vector of structs is the everyday "table of records".
    vector<Student> roster = {
        {"Ana", 88}, {"Ben", 72}, {"Cy", 95}, {"Dee", 81}
    };

    // Sort by score, highest first, using a lambda comparator:
    sort(roster.begin(), roster.end(),
         [](const Student& a, const Student& b) {
             return a.score > b.score;   // descending
         });

    for (const auto& s : roster) {
        cout << s.name << ": " << s.score << endl;
    }
    // Cy: 95
    // Ana: 88
    // Dee: 81
    // Ben: 72
    return 0;
}

// ✅ Expected output:
//    Cy: 95
//    Ana: 88
//    Dee: 81
//    Ben: 72

🔎 Deep Dive: initialization styles & passing structs

You have several ways to fill a struct, each with its place:

struct Point { int x; int y; };

Point a{3, 4};               // aggregate (brace) init -- in order
Point b{.x = 3, .y = 4};     // designated init (C++20) -- named
Point c;                     // default: x, y are uninitialized garbage!
c.x = 3; c.y = 4;            // then assign

Point d = {};                // value-init: x = 0, y = 0

When passing a struct to a function, remember the cost of copying. Pass by const& to read large structs without a copy, and by & when the function must modify the original:

double dist(const Point& p);   // read-only, no copy
void   shift(Point& p, int dx);// modifies the caller's Point

Pro Tips

🧠 Quick Recall

Predict the output before revealing the answer.

struct P { int x; int y; };
P p{2, 5};
cout << p.x * p.y;

10 — brace init sets x = 2, y = 5 in order, so 2 * 5 = 10.

2. Does this compile?

class Box { int v; };
Box b;
b.v = 7;

No — in a class, v is private by default, so b.v is inaccessible. A struct (public by default) would compile.

3. What is printed?

struct R { double w, h; double area() const { return w*h; } };
R r{2.0, 3.0};
cout << r.area();

6 — area() returns w * h = 2.0 * 3.0 = 6. Structs can have member functions.

Common Errors (and the fix)

📋 Quick Reference

TaskCode
Define a structstruct P { int x; int y; };
Brace initP p{3, 4};
Designated init (C++20)P p{.x = 3, .y = 4};
Access a memberp.x
Vector of structsvector<P> pts;
Read big structvoid f(const P& p)

Mini-Challenge: Inventory Value

Design your own Item struct, store several in a vector, and total their value. This is the exact pattern behind carts, ledgers, and dashboards.

#include <iostream>
#include <vector>
#include <string>
using namespace std;

// 🎯 MINI-CHALLENGE: Inventory value
// 1. Define a struct Item with: string name, int quantity, double price.
// 2. Make a vector<Item> with 3 items of your choice.
// 3. Loop with const auto& to compute the TOTAL value
//    (sum of quantity * price across all items).
// 4. Print each item and the grand total.
//
// ✅ Example output:
//    Apple x3 @ 0.5 = 1.5
//    Bread x2 @ 2 = 4
//    Milk x1 @ 1.5 = 1.5
//    Grand total: 7

int main() {
    // your code here
    return 0;
}

🎉 Lesson Complete

Practice quiz

What is a struct in C++?

  • A function that returns multiple values
  • A loop construct
  • A way to bundle several related variables (members) into one named type
  • A pointer to an array

Answer: A way to bundle several related variables (members) into one named type. A struct groups related fields under one name, so you can pass and return them as a single value.

What is the ONLY language-level difference between struct and class in C++?

  • Default member access: struct members are public, class members are private by default
  • structs cannot have functions
  • Only classes can be inherited from
  • structs are stored on the heap

Answer: Default member access: struct members are public, class members are private by default. The sole difference is the default access level (and default inheritance): public for struct, private for class.

How do you access a member m of a struct instance p?

  • p->m
  • p::m
  • m(p)
  • p.m

Answer: p.m. Use the dot operator on a struct object: p.m.

What does this print? struct P { int x; int y; }; P p{2, 5}; cout << p.x * p.y;

  • 7
  • 10
  • 25
  • It does not compile

Answer: 10. Brace init fills members in declaration order, so x = 2 and y = 5, and 2 * 5 = 10.

Does this compile? class Box { int v; }; Box b; b.v = 7;

  • No — in a class, v is private by default, so b.v is inaccessible
  • Yes, v is public
  • Yes, but only inside main
  • No, classes cannot have int members

Answer: No — in a class, v is private by default, so b.v is inaccessible. Class members default to private, so b.v can't be accessed from outside. A struct (public by default) would compile.

Can a struct have constructors and member functions?

  • No, only classes can
  • Only constructors, not member functions
  • Yes — structs can have everything a class can; the choice is about convention
  • Only if marked 'public struct'

Answer: Yes — structs can have everything a class can; the choice is about convention. Structs and classes are equally capable; struct vs class is about intent, not capability.

What does the const mean in double area() const { return w * h; }?

  • The return value cannot change
  • The member function promises not to modify the struct, and can be called on const objects
  • All members become const
  • It makes the function run at compile time

Answer: The member function promises not to modify the struct, and can be called on const objects. A const member function won't modify the object, which documents intent and lets it be called on const instances.

Which initialization style is the C++20 designated initializer for struct Point { int x; int y; };?

  • Point p{3, 4};
  • Point p(3, 4);
  • Point p = 3, 4;
  • Point p{.x = 3, .y = 4};

Answer: Point p{.x = 3, .y = 4};. Designated initializers name each member: Point p{.x = 3, .y = 4}; (C++20).

How should you pass a large struct to a function that only reads it?

  • By value: f(Struct s)
  • By const reference: f(const Struct& s)
  • By pointer to pointer
  • It must be global

Answer: By const reference: f(const Struct& s). const Struct& avoids copying the whole struct on every call while guaranteeing it won't be modified.

Which everyday pattern represents a 'table of records' you can sort with a lambda?

  • A single struct
  • A map of ints
  • A vector of structs (vector<Struct>)
  • A C-style array of chars

Answer: A vector of structs (vector<Struct>). A vector<Struct> holds one record per element and can be sorted with a lambda comparator.

Continue this course

Frequently asked questions

What is a struct in C++?

A struct is a way to bundle several related variables (called members or fields) into a single named type. For example a Point struct can hold an x and a y together, so you can pass and return them as one value instead of juggling loose variables.

What is the real difference between struct and class?

Technically only the default access level differs: struct members are public by default, class members are private by default. By convention C++ programmers use struct for simple, mostly-public data aggregates and class for types with invariants, encapsulation, and behaviour.

Can a struct have functions?

Yes. Structs can have member functions, constructors, and everything a class can. The choice between struct and class is about intent and convention, not capability.

How do I initialize a struct?

You can use aggregate (brace) initialization like Point p{3, 4};, assign members individually after a default construction, or write a constructor. C++20 also allows designated initializers like Point p{.x = 3, .y = 4}; which name each member.

Are structs passed by value or by reference?

By default a struct is copied when passed to a function (by value). For larger structs pass by const reference (const Struct& s) to avoid the copy, and by non-const reference (Struct& s) when the function needs to modify the original.

Related lessons