← Назад к вопросам
В чем разница между классом и структурой?
1.3 Junior🔥 301 комментариев
#Linux и операционные системы
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Разница между классом и структурой в C++
В C++ различие между class и struct минимально, но стилистически и концептуально они используются по-разному.
Синтаксическое различие: Видимость по умолчанию
struct: public по умолчанию
struct Point {
int x; // ✅ public по умолчанию
int y; // ✅ public
void move() {} // ✅ public по умолчанию
};
Point p;
p.x = 10; // ✅ OK — public
p.move(); // ✅ OK
class: private по умолчанию
class Point {
int x; // ❌ private по умолчанию
int y; // ❌ private
void move() {} // ❌ private по умолчанию
};
Point p;
p.x = 10; // ❌ COMPILATION ERROR — private
p.move(); // ❌ COMPILATION ERROR — private
Наследование
struct Base { int x; };
struct Child : Base {};
// наследование PUBLIC по умолчанию
static_assert(std::is_same_v<decltype(Child().x), int>); // ✅ x доступен
class Base { int x; };
class Child : Base {};
// наследование PRIVATE по умолчанию
// Child::x недоступен извне
На практике: стиль кода
Используй struct для:
1. POD типов (Plain Old Data)
struct Point {
double x, y, z;
};
struct TimeStamp {
int year, month, day, hour, minute, second;
};
struct RGB {
uint8_t r, g, b, a;
};
Эти типы:
- Просто хранят данные
- Нет логики поведения
- Могут быть скопированы, сериализованы
- Часто используют
= defaultдля операций
2. Агрегаты с минимальной логикой
struct Person {
std::string name;
int age;
std::string email;
// Может быть конструктор для удобства
Person(std::string n, int a) : name(n), age(a) {}
};
Person p{"Alice", 30};
std::cout << p.name; // ✅ публичные поля OK в structs
3. Функциональные объекты (functors)
struct Compare {
bool operator()(int a, int b) const {
return a < b;
}
};
std::sort(vec.begin(), vec.end(), Compare());
Используй class для:
1. Инкапсуляция и скрытие реализации
class BankAccount {
private:
double balance;
std::vector<Transaction> history;
public:
BankAccount(double initial) : balance(initial) {}
void deposit(double amount) {
if (amount <= 0) throw std::invalid_argument("Amount must be positive");
balance += amount;
history.push_back({amount, "deposit"});
}
double get_balance() const {
return balance;
}
};
BankAccount account(1000);
account.deposit(500); // ✅ OK
// account.balance = 0; // ❌ PRIVATE — не можем!
// account.history.clear(); // ❌ PRIVATE — защитено!
2. Классы с инвариантами
class Vector3D {
private:
double x, y, z; // инварианты невидимы
void validate() const {
if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z)) {
throw std::domain_error("NaN or Inf not allowed");
}
}
public:
Vector3D(double x_, double y_, double z_) : x(x_), y(y_), z(z_) {
validate();
}
double length() const {
return std::sqrt(x*x + y*y + z*z);
}
Vector3D operator+(const Vector3D& v) const {
return Vector3D(x + v.x, y + v.y, z + v.z);
}
};
Vector3D v1{1, 2, 3};
Vector3D v2 = v1 + v1; // ✅ гарантируем инвариант
3. Полиморфизм (виртуальные функции)
class Shape {
public:
virtual ~Shape() = default;
virtual double area() const = 0; // pure virtual
virtual void draw() const = 0;
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override {
return M_PI * radius * radius;
}
void draw() const override {
std::cout << "Drawing circle with r=" << radius << "\n";
}
};
Виртуальные функции обычно private в реализации.
Практический пример: когда выбирать?
// ❌ ПЛОХО: используем struct где нужен class
struct Logger {
std::ofstream file; // внутренняя реализация видна
std::mutex mu; // деталь синхронизации видна
void log(const std::string& msg) {
mu.lock(); // юзер может забыть?
file << msg << "\n";
mu.unlock();
}
};
// ✅ ХОРОШО: используем class
class Logger {
private:
std::ofstream file;
mutable std::mutex mu; // деталь инкапсулирована
public:
void log(const std::string& msg) {
std::lock_guard<std::mutex> lock(mu); // синхронизация скрыта
file << msg << "\n";
}
};
Logger logger;
logger.log("Event"); // ✅ Безопасно
Полный пример: API vs реализация
// --- api.h (публичное API)
class Database {
public:
Database(const std::string& connection_string);
std::optional<User> get_user(int user_id) const;
void save_user(const User& user);
void delete_user(int user_id);
~Database();
private:
// implementation details hidden
class Impl;
std::unique_ptr<Impl> pimpl; // Pimpl idiom
};
// --- database.cpp (реализация)
class Database::Impl {
public:
sqlite3* handle = nullptr;
std::queue<Query> query_queue;
std::thread worker_thread;
std::condition_variable cv;
void connect(const std::string& path) {
// реальное подключение
}
void execute_query(const std::string& sql) {
// исполнение
}
};
Правило выбора
| Критерий | struct | class |
|---|---|---|
| Данные публичны | ✅ | ❌ |
| Требуется инкапсуляция | ❌ | ✅ |
| POD тип | ✅ | ❌ |
| Наследование | rare | common |
| Виртуальные функции | rare | common |
| Инварианты | ❌ | ✅ |
| Функторы | ✅ | можно |
Резюме
Синтаксически:
- struct:
publicпо умолчанию - class:
privateпо умолчанию
Семантически:
- struct: "агрегат данных с минимальной логикой"
- class: "объект с инкапсулированным состоянием и поведением"
Практически:
- Используй struct для POD, data aggregates, простых функторов
- Используй class для объектов с поведением, инкапсуляцией, наследованием
- Если сомневаешься → используй class (безопаснее)
Цитата C++ стандартного комитета:
"Выбор между struct и class — это выбор между предположением, что пользователь будет хорошим гражданином, и гарантией через язык."