← Назад к вопросам

В чем разница между классом и структурой?

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) {
        // исполнение
    }
};

Правило выбора

Критерийstructclass
Данные публичны
Требуется инкапсуляция
POD тип
Наследованиеrarecommon
Виртуальные функцииrarecommon
Инварианты
Функторыможно

Резюме

Синтаксически:

  • struct: public по умолчанию
  • class: private по умолчанию

Семантически:

  • struct: "агрегат данных с минимальной логикой"
  • class: "объект с инкапсулированным состоянием и поведением"

Практически:

  • Используй struct для POD, data aggregates, простых функторов
  • Используй class для объектов с поведением, инкапсуляцией, наследованием
  • Если сомневаешься → используй class (безопаснее)

Цитата C++ стандартного комитета:

"Выбор между struct и class — это выбор между предположением, что пользователь будет хорошим гражданином, и гарантией через язык."