Struct против Class
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 37 из 104.
В C++ struct и class практически идентичны. Оба могут иметь переменные-члены, функции-члены, конструкторы и поддерживать наследование. Единственное различие заключается в их уровне доступа по умолчанию.
В class члены являются private по умолчанию. В struct члены являются public по умолчанию:
struct Point {
int x; // открытый по умолчанию
int y; // открытый по умолчанию
};
class Circle {
double radius; // закрытый по умолчанию
public:
double getRadius() { return radius; }
};Это также относится к наследованию. struct наследуется публично по умолчанию, в то время как class наследуется приватно:
struct DerivedStruct : Base {}; // публичное наследование
class DerivedClass : Base {}; // закрытое наследованиеПомимо этих значений по умолчанию, технической разницы нет. Однако соглашения имеют значение.
Большинство программистов на C++ используют struct для простых контейнеров данных с публичными членами (таких как координаты или конфигурация) и class, когда важны инкапсуляция и поведение. Следование этому соглашению делает намерения вашего кода более понятными для других разработчиков.
Задание
ЛегкоДавайте создадим простую систему конфигурации, которая демонстрирует, когда использовать struct, а когда class, основываясь на соглашениях C++. Вы создадите struct для простых данных, которые должны быть открыто доступны, и class для данных, требующих инкапсуляции и контролируемого доступа.
Для организации кода вы создадите два файла:
Config.h: Определите структуру и класс, представляющие различные типы конфигурационных данных.Сначала создайте
structс именемDimensions— простой контейнер данных для ширины и высоты (оба типаint). Поскольку в структурах члены по умолчанию являются публичными, они должны быть доступны напрямую без геттеров. Добавьте методarea(), который возвращает произведение ширины и высоты.Затем создайте
classс именемAppConfig, который управляет настройками приложения с надлежащей инкапсуляцией. Он должен хранить название приложения (строка) и объектDimensionsдля размера окна. Поскольку члены класса по умолчанию являются приватными, вам нужно будет явно сделать ваш публичный интерфейс доступным. Реализуйте:- Конструктор, принимающий название приложения, ширину и высоту
- Геттер
getAppName(), который возвращает название - Геттер
getWindowSize(), который возвращаетDimensions - Метод
displayConfig(), который выводит:"App: <name>, Window: <width>x<height>, Area: <area>"
main.cpp: Продемонстрируйте разницу между использованием структуры и класса. Считайте название приложения, ширину и высоту из входных данных (три отдельные строки), затем:- Создайте структуру
Dimensionsнапрямую со значениями ширины и высоты — обратитесь к её членам напрямую, чтобы вывести:"Direct struct access: <width> x <height>" - Создайте объект
AppConfigсо всеми тремя значениями - Вызовите
displayConfig(), чтобы показать полную конфигурацию - Используйте геттер для получения размеров окна и выведите:
"Via getter - Area: <area>"
- Создайте структуру
Эта задача подчеркивает соглашение: используйте struct, когда у вас есть простые, прозрачные данные (например, координаты или размеры), и используйте class, когда вы хотите контролировать доступ и добавить поведение вокруг ваших данных.
Преобразуйте входные данные ширины и высоты из строк в целые числа с помощью std::stoi(). Не забудьте про include guards в заголовочном файле.
Шпаргалка
В C++, struct и class практически идентичны, за одним ключевым исключением: их уровень доступа по умолчанию.
В struct члены являются публичными (public) по умолчанию:
struct Point {
int x; // публичный по умолчанию
int y; // публичный по умолчанию
};В class члены являются приватными (private) по умолчанию:
class Circle {
double radius; // приватный по умолчанию
public:
double getRadius() { return radius; }
};Это также относится к наследованию:
struct DerivedStruct : Base {}; // публичное наследование по умолчанию
class DerivedClass : Base {}; // приватное наследование по умолчаниюСоглашение: Используйте struct для простых контейнеров данных с публичными членами, а class — когда важны инкапсуляция и поведение.
Попробуйте сами
#include <iostream>
#include <string>
#include "Config.h"
using namespace std;
int main() {
// Чтение входных данных
string appName;
string widthStr;
string heightStr;
getline(cin, appName);
getline(cin, widthStr);
getline(cin, heightStr);
int width = stoi(widthStr);
int height = stoi(heightStr);
// TODO: Создайте структуру Dimensions с полями width и height
// Обратитесь к её полям напрямую, чтобы вывести: "Direct struct access: <width> x <height>"
// TODO: Создайте объект AppConfig с параметрами appName, width и height
// TODO: Вызовите метод displayConfig() у объекта AppConfig
// TODO: Используйте геттер getWindowSize(), чтобы получить размеры и вывести: "Via getter - Area: <area>"
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнер