← Назад к вопросам
В чём разница между struct и class в C++?
1.3 Junior🔥 151 комментариев
#ООП и проектирование#Структуры данных и алгоритмы#Язык C++
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
В чём разница между struct и class в C++?
В C++, struct и class практически идентичны с точки зрения функциональности. Основная разница — это видимость по умолчанию. Несмотря на синтаксическое сходство, они имеют важные семантические различия в контексте применения.
Основные различия
| Аспект | struct | class |
|---|---|---|
| Видимость членов по умолчанию | public | private |
| Видимость наследования | public | private |
| Когда использовать | Простые структуры данных | Сложные объекты с логикой |
| Семантика | POD-типы (Plain Old Data) | Объекты с инкапсуляцией |
Видимость членов по умолчанию
struct Point {
int x; // public по умолчанию
int y; // public по умолчанию
};
class Person {
std::string name; // private по умолчанию
int age; // private по умолчанию
};
int main() {
Point p;
p.x = 10; // ОК — public
p.y = 20; // ОК — public
Person person;
// person.name = "John"; // ОШИБКА — private
// person.age = 30; // ОШИБКА — private
return 0;
}
Видимость наследования
class Base {
public:
void publicMethod() { }
protected:
void protectedMethod() { }
private:
void privateMethod() { }
};
// Наследование с private (по умолчанию для class)
class DerivedClass : Base {
public:
void test() {
// publicMethod(); // ОШИБКА — стал private
// protectedMethod(); // ОШИБКА — стал private
}
};
// Наследование с public (по умолчанию для struct)
struct DerivedStruct : Base {
public:
void test() {
publicMethod(); // ОК — остался public
// protectedMethod(); // ОК — остался protected
}
};
int main() {
DerivedClass dc;
// dc.publicMethod(); // ОШИБКА — скрыто из-за private наследования
DerivedStruct ds;
ds.publicMethod(); // ОК — открыто через public наследование
return 0;
}
Полный пример с явной видимостью
#include <iostream>
#include <string>
// struct для простых данных
struct Point {
int x;
int y;
Point(int x = 0, int y = 0) : x(x), y(y) {}
void display() const {
std::cout << "(" << x << ", " << y << ")" << std::endl;
}
};
// class для сложной логики
class Rectangle {
private:
double width;
double height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() const {
return width * height;
}
double perimeter() const {
return 2 * (width + height);
}
void setWidth(double w) {
if (w > 0) width = w;
}
void setHeight(double h) {
if (h > 0) height = h;
}
double getWidth() const { return width; }
double getHeight() const { return height; }
};
int main() {
// struct — прямой доступ
Point p(3, 4);
p.display(); // (3, 4)
// class — через методы
Rectangle rect(5.0, 10.0);
std::cout << "Area: " << rect.area() << std::endl;
std::cout << "Perimeter: " << rect.perimeter() << std::endl;
// Валидация данных
rect.setWidth(-5); // Игнорируется
std::cout << "Width: " << rect.getWidth() << std::endl;
return 0;
}
Наследование: явное задание видимости
class Base {
public:
void publicBase() { std::cout << "Public Base" << std::endl; }
};
// Явно указываем видимость наследования
class DerivedPublic : public Base {
// public наследование — открытый интерфейс
};
class DerivedProtected : protected Base {
// protected наследование — для подклассов
};
class DerivedPrivate : private Base {
// private наследование — скрывает базовый интерфейс (композиция)
};
int main() {
DerivedPublic pub;
pub.publicBase(); // ОК
DerivedProtected prot;
// prot.publicBase(); // ОШИБКА — стал protected
DerivedPrivate priv;
// priv.publicBase(); // ОШИБКА — стал private
return 0;
}
Когда использовать struct
1. Простые контейнеры данных (POD типы):
struct Point {
int x, y;
};
struct Color {
int r, g, b, a;
};
struct Date {
int day, month, year;
};
2. Группировка связанных примитивных типов:
struct Rectangle {
float left, top, right, bottom;
};
struct Vector3 {
float x, y, z;
};
3. Небольшие, простые структуры без методов:
struct Pair {
int first;
int second;
};
Когда использовать class
1. Объекты с инкапсуляцией:
class BankAccount {
private:
double balance;
std::string accountNumber;
public:
void deposit(double amount) { /* ... */ }
bool withdraw(double amount) { /* ... */ }
double getBalance() const { /* ... */ }
};
2. Полиморфные типы с виртуальными методами:
class Animal {
public:
virtual void makeSound() = 0;
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
void makeSound() override { /* ... */ }
};
3. Сложная логика с валидацией:
class Person {
private:
std::string name;
int age;
public:
void setAge(int a) {
if (a >= 0 && a <= 150) age = a;
}
};
POD типы (Plain Old Data)
struct часто используется для POD типов:
// POD struct — можно копировать memcpy
struct PODData {
int a;
float b;
char c;
};
// Не POD — содержит нетривиальный деструктор
struct NonPODData {
std::string str; // Имеет свой деструктор
~NonPODData() { }
};
#include <type_traits>
int main() {
// Проверка, является ли тип POD
std::cout << "PODData is POD: "
<< std::is_trivial<PODData>::value << std::endl; // 1 (true)
std::cout << "NonPODData is POD: "
<< std::is_trivial<NonPODData>::value << std::endl; // 0 (false)
return 0;
}
Практический пример: разница в применении
#include <iostream>
#include <vector>
// struct — для данных, которые просто хранятся
struct StudentRecord {
int id;
std::string name;
float gpa;
};
// class — для объектов с логикой
class GradeManager {
private:
std::vector<StudentRecord> students;
float minGPA;
public:
GradeManager(float min = 0.0) : minGPA(min) {}
void addStudent(const StudentRecord& s) {
if (s.gpa >= minGPA) {
students.push_back(s);
}
}
void displayStudents() const {
for (const auto& s : students) {
std::cout << s.name << ": " << s.gpa << std::endl;
}
}
float getAverageGPA() const {
float sum = 0;
for (const auto& s : students) sum += s.gpa;
return students.empty() ? 0 : sum / students.size();
}
};
int main() {
GradeManager manager(2.0);
manager.addStudent({1, "Alice", 3.8});
manager.addStudent({2, "Bob", 2.5});
manager.addStudent({3, "Charlie", 1.5}); // Не добавится
manager.displayStudents();
std::cout << "Average: " << manager.getAverageGPA() << std::endl;
return 0;
}
Рекомендации
- Используй struct для простых контейнеров данных (POD типов)
- Используй class для объектов с логикой и инкапсуляцией
- Будь консистентен — если используешь struct, не добавляй много методов
- Явно указывай видимость — не полагайся на умолчания
- Помни о семантике — выбор влияет на читаемость кода