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() constthat 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 grademember 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
Userwithnew, set its fields via->, print them, thendeletethe 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
Phonestruct 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,authorrather than single letters. - Prefer
std::vectorto 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.