Когда в C++ использовать class, а когда struct? Правила и лучшие практики
Основное различие: модификаторы доступа по умолчанию
Технически в C++ между class и struct есть только одно различие: модификатор доступа по умолчанию.
- struct: все члены и базовые классы по умолчанию
public. - class: все члены и базовые классы по умолчанию
private.
Это означает, что следующие два определения абсолютно идентичны по поведению:
// Вариант 1: struct
struct Point {
int x;
int y;
void print() { /* ... */ }
};
// Вариант 2: class
class Point {
public: // явно указываем public
int x;
int y;
void print() { /* ... */ }
};
Правило большого пальца (Rule of Thumb)
В сообществе C++ сложились следующие негласные конвенции:
- Используйте struct для пассивных структур данных (POD — Plain Old Data). Это объекты, которые просто хранят данные и не имеют инвариантов (сложной логики проверки). Примеры: точки, векторы, цвета, конфигурационные параметры.
- Используйте class для объектов с инвариантами — когда есть логика, защищающая целостность данных (инкапсуляция).
Практические примеры
Когда struct уместен:
// Простая структура данных — все поля открыты
struct Color {
unsigned char r, g, b, a;
};
struct Vec2 {
float x, y;
Vec2 operator+(const Vec2& other) const {
return {x + other.x, y + other.y};
}
};
Когда class обязателен:
// Класс с инвариантами — радиус не может быть отрицательным
class Circle {
private:
double radius;
public:
Circle(double r) {
if (r < 0) throw std::invalid_argument("Radius must be non-negative");
radius = r;
}
double area() const { return 3.14159 * radius * radius; }
// Нет прямого доступа к radius — только через методы
};
Почему это важно?
Использование struct для простых данных — это сигнал другим разработчикам: "Здесь нет магии, просто данные". Когда вы видите struct, вы знаете, что можете свободно читать и изменять поля. class же предупреждает: "Осторожно, здесь есть логика, не трогайте внутренности напрямую".
Дополнительные рекомендации
- Если у структуры есть метод, но он не нарушает инвариант (например,
length()для вектора) — это нормально. Главное — отсутствие скрытой логики. - Избегайте
classсpublic:в начале — это противоречит цели использования класса. - В современном C++ (C++17 и новее) для простых структур часто используют
structс агрегатной инициализацией:Point p{3, 4};
Альтернативный взгляд: не зацикливайтесь на синтаксисе
Некоторые разработчики считают, что различие между class и struct — это просто вопрос стиля, и в больших проектах это не имеет значения. Однако я предлагаю другой подход: думайте о семантике, а не о синтаксисе.
Вместо того чтобы гадать "struct или class", задайте себе вопрос: "Что этот тип представляет?"
- Если это значение (value type) — данные, которые можно копировать и сравнивать — используйте
struct. Примеры: координаты, дата, деньги. - Если это сущность (entity type) — объект с идентичностью и поведением — используйте
class. Примеры: пользователь, заказ, соединение с базой данных.
Заметьте: даже если у структуры есть методы (как у std::complex), она остаётся структурой, потому что это математическое значение. А класс может быть почти пустым (как пустой интерфейс), но всё равно быть классом.
Этот подход хорошо ложится на принципы DDD (Domain-Driven Design) и помогает писать более понятный код. Главное — быть последовательным в рамках одного проекта.
Ответов пока нет.
Войдите чтобы оставить ответ