Menu

Структуры в C++: объединение связанных данных в один тип

Структуры (struct) в C++ простыми словами: как собрать связанные переменные в один тип, объявить и инициализировать объекты структуры, добавить структуре методы и конструкторы, и чем struct на самом деле отличается от class.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Зачем объединять данные

До сих пор каждая переменная существовала сама по себе: int здесь, string там. Но реальные программы имеют дело с вещами, состоящими из нескольких частей: у точки есть x и y, у студента есть имя, возраст и средний балл. Передавать всё это в виде разрозненных, отдельных переменных чревато ошибками; ничто их не связывает, и функция, которой нужны все три, должна принимать все три параметра.

Структура решает эту проблему. Она определяет новый тип, который объединяет связанные переменные — свои поля — в единое целое. После определения вы работаете со всем набором как с одним значением, которое можно хранить, копировать и передавать в функции.

К каждому полю вы обращаетесь через оператор точки (s.name, s.age). Точка с запятой после закрывающей } определения структуры обязательна — её отсутствие одна из самых частых ошибок компиляции у новичков в C++.

Инициализация структуры

Присваивать каждое поле вручную работает, но это многословно и легко забыть какое-нибудь поле. Более чистый вариант — агрегатная инициализация: перечислите значения в фигурных скобках в том же порядке, в каком объявлены поля.

Остерегайтесь пустого случая по умолчанию: Point p; (без скобок) оставляет x и y с мусорными значениями, потому что поля встроенных типов не обнуляются автоматически. Point p{}; инициализирует их значением 0. Предпочитайте скобки. Можно также зашить значения по умолчанию прямо в определение, чтобы даже Point p; начинал с чистого состояния:

Структуры как параметры функций

Структура — это одно значение, поэтому функция может принимать один параметр вместо трёх. Только помните, что передача структуры по значению копирует все её поля. Для всего, что больше пары int'ов, передавайте по const-ссылке, чтобы избежать копирования — то же правило, которое вы видели на странице про ссылки.

Возврат целой структуры из функции — идиоматичный способ вернуть сразу несколько значений, гораздо чище, чем жонглировать несколькими выходными ссылками.

Добавление методов и конструкторов

Структура не ограничивается данными. Она может содержать методы, работающие с её собственными полями, и конструктор, который инициализирует объект в момент его создания. Здесь структура начинает выглядеть как небольшой объект с поведением.

Внутри метода к полям обращаются по имени (width, height) — они ссылаются на копию этого объекта. Пометка area() const сообщает компилятору, что функция только читает объект, что позволяет вызывать её и для значений const Rectangle. Конструкторы — тема сама по себе, включая синтаксис списка инициализации : width(w); страница про конструкторы разбирает её подробно.

struct vs. class: настоящее различие

Возможно, вы слышали, что «структуры для данных, классы для объектов». Это соглашение, а не правило языка. В C++ struct и class почти одно и то же — единственное встроенное различие в уровне доступа по умолчанию.

struct S {
    int x;        // public по умолчанию
};

class C {
    int x;        // private по умолчанию
};

Поля struct являются public, если вы не пометите их иначе; поля class начинаются с private. Вот и всё — у обоих могут быть конструкторы, методы, наследование и всё остальное. Вы даже можете добавить структуре явные спецификаторы доступа, чтобы скрыть поля:

Практический вывод: используйте struct для прозрачных наборов данных, где каждое поле предназначено для свободного доступа (Point, Color, запись конфигурации), и обращайтесь к class, когда хотите защитить внутреннее состояние за публичным интерфейсом. Компилятор обращается с ними одинаково; ключевое слово лишь сигнализирует о вашем намерении.

Массивы и векторы структур

Поскольку структура — обычный тип, вы можете поместить множество структур в массив или вектор и пройтись по ним в цикле, как по любому другому значению.

Обратите внимание на вложенные скобки: каждый {"Keyboard", 49.99} агрегатно инициализирует один Product, а внешние скобки строят вектор. Использование const Product& в цикле for по диапазону избавляет от копирования каждой структуры на каждой итерации — уберите &, и вы будете без нужды дублировать каждый элемент.

Далее: перечисления (Enums)

Структуры позволяют строить тип из нескольких объединённых значений. Следующая глава идёт в обратном направлении: перечисление (enum) определяет тип, который может содержать ровно одно значение из небольшого именованного набора — идеально для таких вещей, как Color::Red, Direction::North или статус конечного автомата. Вы увидите, как enum class даёт читаемые, типобезопасные константы, которые естественно сочетаются со структурами и классами, которые вы теперь создаёте.

Часто задаваемые вопросы

Что такое структура (struct) в C++?

struct — это пользовательский тип, который объединяет несколько связанных переменных (называемых полями, или members) под одним именем. Вместо того чтобы жонглировать отдельными переменными string name, int age и double gpa, вы собираете их в единый тип Student и передаёте один объект. Структура также может содержать методы и конструкторы — в современном C++ это полноценный класс, поля которого по умолчанию public.

В чём разница между struct и class в C++?

Технически только в уровне доступа по умолчанию: поля struct являются public, если не указано иное, тогда как поля class по умолчанию private. То же касается наследования. Всё остальное — конструкторы, методы, наследование — работает одинаково. По соглашению программисты используют struct для простых наборов данных, а class — для типов с инвариантами и скрытыми внутренними деталями.

Как инициализировать структуру в C++?

Самый простой способ — агрегатная инициализация в фигурных скобках в порядке объявления полей: Point p{3, 4};. Можно также присвоить каждое поле вручную через оператор точки (p.x = 3;), задать полям значения по умолчанию прямо в определении (int x = 0;) или написать конструктор, чтобы структура настраивала себя сама. Инициализация в фигурных скобках предпочтительна, потому что она не оставляет поля молча неинициализированными.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ