У яких сценаріях краще використовувати struct
vs vs a class
в C ++?
У яких сценаріях краще використовувати struct
vs vs a class
в C ++?
Відповіді:
Відмінності між a class
і a struct
в C ++ полягають у тому, що структури мають public
члени за замовчуванням, а бази, а класи мають типові private
члени та бази. Обидва класи і структури можуть мати суміш public
, protected
і private
члени, можуть використовувати успадкування та можуть мати функції - члени.
Я рекомендую використовувати структури як структуру простих старих даних без будь-яких класоподібних особливостей, а також використовувати класи як агрегатні структури private
даних з функціями даних та членів.
Як зазначають усі, існують лише дві фактичні мовні відмінності:
struct
за замовчуванням для загальнодоступного та class
за замовчуванням для приватного доступу.struct
за замовчуванням до public
спадкування та class
за замовчуванням - до private
спадкування. (За іронією долі, як і для багатьох речей у C ++, за замовчуванням відбувається зворотній бік: public
успадкування - це набагато частіший вибір, але люди рідко декларують struct
s лише для того, щоб заощадити на введенні public
ключового слова.Але реальна різниця в практиці полягає між a class
/, struct
що оголошує конструктор / destructor, і тим, що не робить. Існують певні гарантії типу POD "звичайні старі дані", які більше не застосовуються, коли ви переймаєте конструкцію класу. Щоб це розрізнення було зрозумілим, багато людей навмисно використовують лише struct
s для типів POD, і, якщо вони взагалі збираються додавати якісь методи, використовують class
es. Різниця між двома фрагментами, наведеними нижче, інакше безглузда:
class X
{
public:
// ...
};
struct X
{
// ...
};
(До речі, ось нитка з кількома хорошими поясненнями про те, що насправді означає "тип POD": Що таке типи POD у C ++? )
struct
чи class
не маєте жодного стосунку до того, чи є ваш об'єкт POD або ви повинні визначити конструктор копій / деструктор копій. Функції членів також не мають жодного стосунку до того, що це "POD". Перечитуючи те, що ви написали, я бачу, що ви не пропонуєте інакше, але ця редакція заплутана
У існуючих відповідях існує багато помилок.
Обидва class
і struct
оголошують клас.
Так, можливо, вам доведеться переставити ключові слова, що змінюють доступ, всередині визначення класу, залежно від того, яке ключове слово ви використовували для оголошення класу.
Але, крім синтаксису, єдиною причиною вибору одного над іншим є умовність / стиль / уподобання.
Дехто любить дотримуватися struct
ключового слова для класів без членських функцій, оскільки отримане визначення "схоже" на просту структуру від C.
Аналогічно, деякі люди люблять використовувати class
ключове слово для класів з членами функцій та private
даних, оскільки на ньому написано "клас" і тому схоже на приклади їх улюбленої книги з об'єктно-орієнтованого програмування.
Реальність полягає в тому, що це повністю залежить від вас і вашої команди, і це не матиме жодної різниці для вашої програми.
Наступні два класи абсолютно рівнозначні всім, крім їх назви:
struct Foo
{
int x;
};
class Bar
{
public:
int x;
};
Ви можете навіть перемикати ключові слова під час повторного декларування:
class Foo;
struct Bar;
(хоча ця функція Visual Studio будується через невідповідність, тому компілятор видасть попередження, коли ви це зробите.)
і наступні вирази оцінюють як істинні:
std::is_class<Foo>::value
std::is_class<Bar>::value
Зауважте, проте, що ви не можете перемикати ключові слова під час перевизначення ; це лише тому, що (згідно з правилом однієї дефініції) дублюючі визначення класів через одиниці перекладу повинні "складатися з тієї ж послідовності лексем" . Це означає , що ви не можете навіть обмінюватися const int member;
з int const member;
, і не має нічого спільного з семантикою class
або struct
.
class foo { public: ... };
а інший - той, struct foo { ... };
який повинен відповідати істині відповідно до "абсолютно еквівалентної" заяви. Вона приходить до причини , що неповні декларації struct foo;
і class foo;
є взаємозамінними. Вони не визначають тіло класу, і тому вони нічого не говорять про макет доступу.
Foo
і Bar
по - , як і раніше еквівалентні / однакові типи. Я обов'язково сказав "при переоформленні " і навести приклад. Подумайте над цим, я поясню це у відповіді, щоб переконатись, що я не вводив людей у бік UB
Єдиний раз, коли я використовую структуру замість класу, - це коли оголошувати функтор прямо перед тим, як використовувати його у виклику функції, і хочу мінімізувати синтаксис задля наочності. наприклад:
struct Compare { bool operator() { ... } };
std::sort(collection.begin(), collection.end(), Compare());
Учасники та базові класи структури за замовчуванням є загальнодоступними, тоді як у класі вони за замовчуванням приватні. Примітка: ви повинні робити базові класи явно публічними, приватними чи захищеними, а не покладатися на типові параметри.
Структура та клас інакше функціонально еквівалентні.
Гаразд, досить цього писку чистого техно-розмови. Емоційно більшість розробників чітко розрізняють клас та структуру. Структура просто відчуває себе відкритою купою бітів з дуже маленьким способом інкапсуляції чи функціональності. Клас відчуває себе живим і відповідальним членом суспільства з інтелектуальними послугами, сильним бар'єром інкапсуляції та чітко визначеним інтерфейсом. Оскільки це конотація у більшості людей, ви, ймовірно, повинні використовувати ключове слово stru, якщо у вас є клас, який має дуже мало методів і має загальнодоступні дані (такі речі існують у добре розроблених системах!), Але в іншому випадку ви, ймовірно, повинні використовувати клас ключове слово.
Одне місце, де структура була для мене корисною - це коли у мене є система, яка отримує повідомлення з фіксованим форматом (скажімо, послідовний порт) від іншої системи. Ви можете передати потік байтів у структуру, яка визначає ваші поля, а потім легко отримати доступ до полів.
typedef struct
{
int messageId;
int messageCounter;
int messageData;
} tMessageType;
void processMessage(unsigned char *rawMessage)
{
tMessageType *messageFields = (tMessageType *)rawMessage;
printf("MessageId is %d\n", messageFields->messageId);
}
Очевидно, це те саме, що ви робили в C, але я вважаю, що накладні витрати на декодування повідомлення в клас зазвичай не варті.
operator >>
на занятті замість того, щоб писати processMessage
функцію, яка зробить ваш C ++ більш схожим на правильний C ++ та менш схожий на C.
__packed__
структуру та мати невідомі для реалізації ifdef (вам потрібно перевернути замовлення на машині, де цілеспрямованість протилежна зовнішньому джерелу даних надає). Це не дуже, але я звик упаковувати / розпаковувати регістри для віддалених периферійних пристроїв на вбудованих платформах портативно.
char
тип, який звільнений від псевдоніму. Однак існує проблема, хоч і інша: якщо char*
передати інший тип, якщо на цій адресі не було насправді жодного об'єкта останнього типу, це UB, оскільки він порушує правила життя. Афаїк, навіть якщо тип призначення тривіально сконструйований, просто виділення пам'яті недостатньо для C ++, щоб офіційно дозволити трактувати цю пам'ять як цей тип.
Ви можете використовувати "struct" в C ++, якщо ви пишете бібліотеку, внутрішньою частиною якої є C ++, але API можна викликати або C, або C ++ кодом. Ви просто створюєте один заголовок, який містить структури та глобальні функції API, які ви піддаєте і коду C, і C ++ таким чином:
// C access Header to a C++ library
#ifdef __cpp
extern "C" {
#endif
// Put your C struct's here
struct foo
{
...
};
// NOTE: the typedef is used because C does not automatically generate
// a typedef with the same name as a struct like C++.
typedef struct foo foo;
// Put your C API functions here
void bar(foo *fun);
#ifdef __cpp
}
#endif
Тоді ви можете записати функціональну панель () у файл C ++, використовуючи код C ++ і зробити його дзвінким із C, і два світи можуть обмінюватися даними через оголошені структури. Звичайно, є інші застереження при змішуванні C і C ++, але це спрощений приклад.
Як кажуть всі, єдиною реальною різницею є доступ за замовчуванням. Але я особливо використовую структуру, коли я не хочу будь-якої інкапсуляції з простим класом даних, навіть якщо я реалізую деякі допоміжні методи. Наприклад, коли мені потрібно щось подібне:
struct myvec {
int x;
int y;
int z;
int length() {return x+y+z;}
};
Щоб відповісти на моє власне запитання (безсоромно), Як вже було сказано, права доступу мають єдину різницю між ними у C ++.
Я схильний використовувати структуру лише для зберігання даних. Я дозволю йому отримати кілька допоміжних функцій, якщо це полегшить роботу з даними. Однак як тільки для даних потрібен контроль потоку (тобто геттери / сеттери, які підтримують або захищають внутрішній стан) або починає набувати будь-якої основної функціональності (в основному більш об'єктоподібної), вона буде «модернізована» до класу, щоб краще спілкуватися з намірами.
Структури ( POD , загалом) зручні, коли ви надаєте сумісний з C інтерфейс із реалізацією C ++, оскільки вони переносяться через мовні межі та формати лінкерів.
Якщо це вас не турбує, я вважаю, що використання "struct" замість "class" є хорошим комунікатором наміру (як @ZeroSignal сказав вище). Структури також мають більш передбачувану семантику копіювання, тому вони корисні для даних, які ви збираєтесь записувати на зовнішні носії або надсилати по всій мережі.
Структури також зручні для різних завдань метапрограмування, як шаблони ознак, які просто розкривають купу залежних типівdedefs:
template <typename T> struct type_traits {
typedef T type;
typedef T::iterator_type iterator_type;
...
};
... Але це справді просто користь рівня захисту за замовчуванням структури, що є публічним ...
Для C ++ насправді немає великої різниці між структурами та класами. Основна функціональна відмінність полягає в тому, що члени структури за замовчуванням є загальнодоступними, тоді як вони є приватними за замовчуванням у класах. Інакше, що стосується мови, вони є рівнозначними.
При цьому я схильний використовувати структури в C ++, як і в C #, подібно до того, що сказав Брайан. Структури - це прості контейнери даних, тоді як класи використовуються для об'єктів, яким потрібно діяти на даних, крім того, щоб просто їх утримувати.
Вони майже однакове. Завдяки магії C ++, структура може утримувати функції, використовувати успадкування, створені за допомогою "нового" тощо, як клас
Єдина функціональна відмінність полягає в тому, що клас починається з прав приватного доступу, тоді як структура починається з загальнодоступних. Це підтримує зворотну сумісність із C.
На практиці я завжди використовував структури як власники даних, а класи - як об'єкти.
Як вказували інші
Існує чітка рекомендація про те, коли використовувати Stroustrup / Sutter:
Однак майте на увазі, що нерозумно передати заяву про що-небудь. як клас ( class X;
) та визначте його як struct ( struct X { ... }
). Він може працювати на деяких лінкерах (наприклад, g ++), а на інших (наприклад, MSVC) може не працювати, тож ви опинитесь у пеклі розробника.
class Foo; struct Foo { void bar() {} }; int main() { Foo().bar(); }
не тільки компілюється та працює з MSVC 2017, але навіть створює чітке попередження, яке Foo
було оголошено як, struct
але визначено як class
. Але я також добре пам’ятаю, що коштувало нашій команді півдня на пошук того дурного клопа. Я не впевнений, яку версію MSVC ми використовували тоді.
class
чи struct
про пряму декларацію, і обидві вільно взаємозамінні відповідно до стандарту (хоча відомо, що VS попереджає; я завжди припускав, що це просто уникнути явних помилок програміста). Щось тут не пахне. Ви впевнені, що це не помилка порушення ODR?
struct
-наперед class
-наперед, проблеми пішли. На сьогоднішній день я теж вважаю це дивним. Буду радий, якби ви могли пролити трохи світла на це.
Учасники класу за замовчуванням приватні.
class test_one {
int main_one();
};
Еквівалентно
class test_one {
private:
int main_one();
};
Тож якщо спробувати
int two = one.main_one();
Ми отримаємо помилку: main_one is private
оскільки її недоступно. Ми можемо вирішити його, ініціалізуючи його, вказавши його загальнодоступну, тобто
class test_one {
public:
int main_one();
};
Структура - це клас, де учасники за замовчуванням є загальнодоступними.
struct test_one {
int main_one;
};
Значить main_one
приватне, тобто
class test_one {
public:
int main_one;
};
Я використовую структури для структур даних, де члени можуть приймати будь-яке значення, так простіше.
Перевага struct
над class
тим, що він зберігає один рядок коду, якщо він дотримується "спочатку публічних членів, а потім приватних". У цьому світлі я вважаю ключове слово class
марним.
Ось ще одна причина використання лише struct
та ніколи class
. Деякі настанови стилю коду для C ++ пропонують використовувати малі букви для функцій макросів. Обгрунтування полягає в тому, що коли макрос перетворюється на функцію вбудованого, ім'я не потрібно змінювати. Те ж саме. У вас є гарна структура в стилі С і одного дня ви дізнаєтесь, що вам потрібно додати конструктор або якийсь зручний метод. Ви змінюєте його на class
? Скрізь?
Розрізняти struct
s і class
es - це занадто багато клопоту, вступаючи в спосіб робити те, що ми повинні робити - програмування. Як і у багатьох проблем C ++, вона виникає із сильного прагнення до зворотної сумісності.
class
? Ви думали, що клас, визначений struct
ключовим словом, не може мати функцій-членів або конструктора?
joe()
повинен визначатися з class
ключовим словом? Кожен клас, що має щонайменше 4 int
членів, повинен визначатися struct
ключовим словом?
struct
, а агрегати з методами визначені class
". Занадто багато клопоту.
вони однакові з різними типовими налаштуваннями (приватні за замовчуванням для class
та публічні за замовчуванням для struct
), тому теоретично вони абсолютно взаємозамінні.
тому, якщо я просто хочу запакувати якусь інформацію, щоб рухатись, я використовую структуру, навіть якщо я поклав туди кілька методів (але не багато). Якщо це в основному непрозора річ, де головне використання буде за допомогою методів, а не безпосередньо для членів даних, я використовую повний клас.
Структури за замовчуванням мають загальнодоступний доступ, а класи за замовчуванням мають приватний доступ.
Особисто я використовую структури для об'єктів передачі даних або як об'єкти цінності. При використанні як такого я оголошую всіх членів як const для запобігання модифікації іншим кодом.
Обидва , struct
і class
один і ті ж під капотом , хоча з різним по замовчуванням як для видимості, по struct
замовчуванням є публічним і по class
замовчуванням є приватним. Ви можете змінити будь-який на інший, використовуючи private
і public
. Вони обидва дозволяють успадкування, методи, конструктори, деструктори та все інше, що вигідно об'єктно-орієнтованої мови.
Однак одна величезна відмінність між ними полягає struct
в тому, що як C підтримується ключове слово, тоді як class
це не так. Це означає , що один можна використовувати struct
в включається файл , який може бути #include
в будь-який C ++ або C до тих пір , як struct
це звичайний стиль C struct
і все інше в інклюдніке сумісний з C, тобто не C ++ конкретні ключові слова , такі як private
, public
, немає методи, відсутність успадкування тощо. тощо.
Стиль змінного струму struct
можна використовувати з іншими інтерфейсами, які підтримують стиль C struct
для перенесення даних по інтерфейсу і назад.
Стиль змінного струму struct
- це певний шаблон (не шаблон C ++, а скоріше візерунок або трафарет), який описує компонування області пам'яті. На протязі багатьох років інтерфейси придатними для використання C і C плагінів (тут дивиться на вас Java і Python і Visual Basic) були створені деякі з яких працюють в стилі C struct
.
Технічно обидва в C ++ однакові - наприклад, структура може перевантажувати операторів тощо.
Однак:
Я використовую структури, коли хочу передавати інформацію декількох типів одночасно, я використовую класи, коли я маю справу з "функціональним" об'єктом.
Сподіваюся, це допомагає.
#include <string>
#include <map>
using namespace std;
struct student
{
int age;
string name;
map<string, int> grades
};
class ClassRoom
{
typedef map<string, student> student_map;
public :
student getStudentByName(string name) const
{ student_map::const_iterator m_it = students.find(name); return m_it->second; }
private :
student_map students;
};
Наприклад, я повертаю студента структури в методах get ... () тут - насолоджуйтесь.
Коли ви вирішили використовувати структура та коли використовувати клас у C ++?
Я використовую, struct
коли визначаю functors
і POD
. Інакше використовую class
.
// '()' is public by default!
struct mycompare : public std::binary_function<int, int, bool>
{
bool operator()(int first, int second)
{ return first < second; }
};
class mycompare : public std::binary_function<int, int, bool>
{
public:
bool operator()(int first, int second)
{ return first < second; }
};
std::binary_function<>
не просто застаріла, c ++ 17 навіть усуває її.
Усі члени класу за замовчуванням приватні, а всі члени структури за замовчуванням є загальнодоступними. Клас має приватні бази за замовчуванням, а Struct - загальнодоступні загальнодоступні бази. Структура у випадку C не може мати функцій-членів, де, як і у випадку C ++, у структуру можна додавати функції-учасники. Крім цих відмінностей, я не знаходжу в них нічого дивного.
Я використовую структуру лише тоді, коли мені потрібно зберігати деякі дані без будь-яких функцій-членів, пов'язаних з нею (для роботи над даними-членами) та безпосередньо для доступу до змінних даних.
Наприклад: читання / запис даних з файлів та потоків сокет тощо. Передача аргументів функції в структуру, де аргументів функції занадто багато, а синтаксис функції виглядає занадто тривалим.
Технічно немає великої різниці між класом і struture, крім доступності за замовчуванням. Більше цього залежить від стилю програмування, яким чином ви ним користуєтеся.
Я думав, що Структури призначені як Структура даних (на зразок масиву даних з декількома даними), а класи вкладаються для пакетування кодів (як колекції підпрограм і функцій).
:(
Я ніколи не використовую "struct" в C ++.
Я ніколи не можу уявити сценарій, коли ти використовував би структуру, коли хочеш приватних членів, якщо тільки ти навмисно не намагаєшся заплутатись.
Здається, що використання структур є скоріше синтаксичним вказівкою на те, як будуть використовуватися дані, але я б краще просто створити клас і спробувати зробити це явним в імені класу або через коментарі.
Напр
class PublicInputData {
//data members
};
struct
вже досить явним, що члени класу за замовчуванням будуть загальнодоступними?