У яких сценаріях краще використовувати structvs vs a classв C ++?
У яких сценаріях краще використовувати structvs vs a classв C ++?
Відповіді:
Відмінності між a classі a structв C ++ полягають у тому, що структури мають publicчлени за замовчуванням, а бази, а класи мають типові privateчлени та бази. Обидва класи і структури можуть мати суміш public, protectedі privateчлени, можуть використовувати успадкування та можуть мати функції - члени.
Я рекомендую використовувати структури як структуру простих старих даних без будь-яких класоподібних особливостей, а також використовувати класи як агрегатні структури privateданих з функціями даних та членів.
Як зазначають усі, існують лише дві фактичні мовні відмінності:
structза замовчуванням для загальнодоступного та classза замовчуванням для приватного доступу.structза замовчуванням до publicспадкування та classза замовчуванням - до privateспадкування. (За іронією долі, як і для багатьох речей у C ++, за замовчуванням відбувається зворотній бік: publicуспадкування - це набагато частіший вибір, але люди рідко декларують structs лише для того, щоб заощадити на введенні publicключового слова.Але реальна різниця в практиці полягає між a class/, structщо оголошує конструктор / destructor, і тим, що не робить. Існують певні гарантії типу POD "звичайні старі дані", які більше не застосовуються, коли ви переймаєте конструкцію класу. Щоб це розрізнення було зрозумілим, багато людей навмисно використовують лише structs для типів POD, і, якщо вони взагалі збираються додавати якісь методи, використовують classes. Різниця між двома фрагментами, наведеними нижче, інакше безглузда:
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? Скрізь?
Розрізняти structs і classes - це занадто багато клопоту, вступаючи в спосіб робити те, що ми повинні робити - програмування. Як і у багатьох проблем 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вже досить явним, що члени класу за замовчуванням будуть загальнодоступними?