Structures in C++ (the struct
type) let you group related variables into a single user-defined type.
They make programs more readable and maintainable by bundling data that logically belongs together.
🔹 Defining and Using a struct
A struct
can contain multiple fields (members) of different types. You can declare variables of that struct and access members with the dot operator (.
).
#include <iostream>
#include <string>
struct Book {
std::string title;
std::string author;
int pages;
};
int main() {
Book b{ "The C++ Way", "Alex Author", 350 };
std::cout << b.title << " by " << b.author << " (" << b.pages << " pages)\n";
}
Output
The C++ Way by Alex Author (350 pages)
📝 Try it Yourself: Add a
price
(double) member toBook
, initialize it, and print it with two decimal places using<< std::fixed << std::setprecision(2)
(remember to include<iomanip>
).
1. Initializing Structures (Aggregate Init)
Structs support aggregate initialization with braces in declaration order. You can also default-initialize first and assign later. This helps keep code concise and clear.
#include <iostream>
#include <string>
struct Book {
std::string title;
std::string author;
int pages;
};
int main() {
// Aggregate initialization (order matches member declaration)
Book a{ "Title A", "Author A", 123 };
// Default initialization, then assignment
Book b; // members default-constructed
b.title = "Title B";
b.author = "Author B";
b.pages = 456;
std::cout << a.title << " | " << a.author << " | " << a.pages << "\n";
std::cout << b.title << " | " << b.author << " | " << b.pages << "\n";
}
Output
Title A | Author A | 123
Title B | Author B | 456
📝 Try it Yourself: Create an array
Book library[3]
using aggregate initialization for each element, then loop to print all titles and authors.
2. Methods, Constructors, and Default Values
In C++, struct
can have constructors and member functions—just like class
. The only difference is default access:
struct
members are public by default; class
members are private by default.
#include <iostream>
struct Point {
int x = 0;
int y = 0;
Point() = default;
Point(int x, int y) : x(x), y(y) {}
void move(int dx, int dy) { x += dx; y += dy; }
};
int main() {
Point p{2, 3};
p.move(1, -1);
std::cout << "(" << p.x << "," << p.y << ")\n"; // (3,2)
}
Output
(3,2)
📝 Try it Yourself: Add a method
double distFromOrigin() const
that returnsstd::sqrt(x*x + y*y)
(include<cmath>
) and print the result.
3. Arrays, Vectors, and Passing by Reference
For collections of structs, you can use C-style arrays or prefer std::vector
for safety and flexibility.
Pass large structs by const&
to avoid copies, and by non-const reference when you intend to modify them.
#include <vector>
#include <string>
#include <iostream>
struct Student {
std::string name;
int age;
};
void printStudent(const Student& s) {
std::cout << s.name << " (" << s.age << ")\n";
}
int main() {
std::vector<Student> cls = { {"Ava", 20}, {"Ben", 21}, {"Cleo", 19} };
for (const auto& s : cls) {
printStudent(s);
}
}
Output
Ava (20)
Ben (21)
Cleo (19)
📝 Try it Yourself: Add a
double grade
member toStudent
, store three grades, and compute the average grade by iterating the vector.
4. Pointers to struct and the Arrow Operator
When you have a pointer to a struct, use ->
to access members through the pointer.
This is equivalent to dereferencing then using the dot operator ((*ptr).member
).
#include <iostream>
#include <string>
struct User {
std::string name;
int id;
};
int main() {
User u{ "Nora", 101 };
User* p = &u;
std::cout << p->name << " #" << p->id << "\n"; // via arrow
std::cout << (*p).name << " #" << (*p).id << "\n"; // equivalent via dereference
}
Output
Nora #101
Nora #101
📝 Try it Yourself: Dynamically allocate a
User
withnew
, set its fields via->
, print them, thendelete
the pointer and set it tonullptr
.
5. Nested and Composite Structs
Structs can contain other structs, enabling rich, hierarchical data models (e.g., an Address
inside a Person
).
#include <iostream>
#include <string>
struct Address {
std::string city;
std::string country;
};
struct Person {
std::string name;
Address addr;
};
int main() {
Person p{ "Iris", {"Berlin", "Germany"} };
std::cout << p.name << " - " << p.addr.city << ", " << p.addr.country << "\n";
}
Output
Iris - Berlin, Germany
📝 Try it Yourself: Add a
Phone
struct and include it as a member ofPerson
. Initialize and print all contact details.
6. Best Practices and Common Mistakes
- Use clear member names: Prefer descriptive names like
pages
,author
rather than single letters. - Prefer
std::vector
to raw arrays: It manages memory and knows its size. - Pass large structs by
const&
: Avoid copies when you don’t need to modify the data. - Initialize members: Provide default member initializers or constructors to keep objects valid.
- Be mindful of ownership: If your struct holds pointers or resources, define proper constructors/destructors or use smart pointers.
🔹 Frequently Asked Questions (FAQ)
Q: What’s the difference between struct
and class
in C++?
A: Only default access differs. struct
defaults to public members; class
defaults to private. Otherwise, they have the same capabilities.
Q: Can a struct have methods and constructors?
A: Yes. Structs in C++ can have constructors, methods, static members, and even inheritance—just like classes.
Q: Should I return a struct by value or by reference?
A: For small structs, returning by value is simple and efficient (RVO/move). For large structs, consider const&
when no copy is needed.
Q: Can I use struct
for complex types?
A: Yes. Use struct
for plain data aggregates or simple types; use class
when you need encapsulation. This is often a style choice.