W jakich scenariuszach lepiej jest używać struct
vs class
w C ++?
W jakich scenariuszach lepiej jest używać struct
vs class
w C ++?
Odpowiedzi:
Różnice między class
ai struct
w C ++ polegają na tym, że struktury mają domyślne public
elementy i bazy, a klasy mają domyślne private
elementy i bazy. Obie klasy i kodowanym może mieć mieszankę public
, protected
iprivate
członkowie mogą korzystać z dziedziczenia i mogą mieć funkcje składowe.
Poleciłbym używanie struktur jako zwykłych struktur danych bez żadnych funkcji podobnych do klas, i używanie klas jako agregujących struktur private
danych z danymi i funkcjami składowymi.
Jak wszyscy zauważają, w rzeczywistości istnieją tylko dwie rzeczywiste różnice językowe:
struct
domyślnie dostęp publiczny i class
domyślny dostęp prywatny.struct
domyślnie przyjmuje public
dziedziczenie i class
domyślnie private
dziedziczenie. (Jak na ironię, podobnie jak w przypadku wielu rzeczy w C ++, domyślnie jest to wstecz: public
dziedziczenie jest zdecydowanie bardziej powszechnym wyborem, ale ludzie rzadko deklarują, struct
że oszczędzają na wpisaniu public
słowa kluczowego „ ”.Ale prawdziwa różnica w praktyce między class
/ struct
, który deklaruje konstruktora / destruktora i jeden, który nie. Istnieją pewne gwarancje na POD typu „zwykłe stare dane”, które nie obowiązują już po przejęciu konstrukcji klasy. Aby zachować to rozróżnienie, wiele osób celowo używa tylko struct
s dla typów POD, a jeśli zamierzają w ogóle dodać jakiekolwiek metody, używają class
es. Różnica między dwoma fragmentami poniżej jest bez znaczenia:
class X
{
public:
// ...
};
struct X
{
// ...
};
(Nawiasem mówiąc, oto wątek z kilkoma dobrymi objaśnieniami, co tak naprawdę oznacza „typ POD”: Co to są typy POD w C ++? )
struct
lub class
nie ma żadnego wpływu na to, czy obiekt POD czy należy zdefiniować konstruktor kopiuj / destruktora. Funkcje składowe również nie mają wpływu na to, że coś jest POD. Kiedy ponownie czytam to, co napisałeś, widzę, że nie sugerujesz inaczej, ale obecne sformułowanie jest mylące
Istnieje wiele nieporozumień w istniejących odpowiedziach.
Zarówno class
i struct
deklarują klasę.
Tak, może być konieczne przestawienie słów kluczowych modyfikujących dostęp w definicji klasy, w zależności od słowa kluczowego użytego do zadeklarowania klasy.
Ale poza składnią jedynym powodem, aby wybierać między innymi, jest konwencja / styl / preferencja.
Niektórzy ludzie lubią trzymać się struct
słowa kluczowego dla klas bez funkcji składowych, ponieważ wynikowa definicja „wygląda jak” prosta struktura z C.
Podobnie, niektórzy ludzie lubią używać class
słowa kluczowego dla klas z funkcjami i private
danymi składowymi, ponieważ na nim jest napisane „klasa”, a zatem wyglądają jak przykłady z ich ulubionych książek na temat programowania obiektowego.
Rzeczywistość jest taka, że to całkowicie zależy od ciebie i twojego zespołu, i to dosłownie nie zrobi żadnej różnicy dla twojego programu.
Poniższe dwie klasy są absolutnie równoważne pod każdym względem oprócz ich nazwy:
struct Foo
{
int x;
};
class Bar
{
public:
int x;
};
Możesz nawet przełączać słowa kluczowe podczas ponownego tworzenia:
class Foo;
struct Bar;
(chociaż powoduje to uszkodzenie kompilacji Visual Studio z powodu niezgodności, więc kompilator wyświetli ostrzeżenie po wykonaniu tej czynności).
a następujące wyrażenia mają wartość true:
std::is_class<Foo>::value
std::is_class<Bar>::value
Pamiętaj jednak, że nie można zmieniać słów kluczowych podczas redefiniowania ; dzieje się tak tylko dlatego, że (zgodnie z regułą jednej definicji) zduplikowane definicje klas w jednostkach tłumaczeniowych muszą „składać się z tej samej sekwencji tokenów” . Oznacza to, że nie możesz nawet wymieniać const int member;
się int const member;
i nie ma to nic wspólnego z semantyką class
lub struct
.
class foo { public: ... };
a inna może mieć, struct foo { ... };
co musiałoby być zgodne z twierdzeniem „absolutnie równoważnym”. Chodzi o przyczyny, że niepełne oświadczenia struct foo;
i class foo;
są wymienne. Nie określają one treści klasy, więc nie mówią nic o układzie dostępu.
Foo
i Bar
nadal są równoważne / identyczne typy. Upewniłem się, że powiedziałem „przy ponownym zgłaszaniu ” i podałem przykład. Pomyśl o tym, wyjaśnię to w odpowiedzi, aby upewnić się, że nie wprowadzam ludzi w błąd UB
Jedynym razem, gdy używam struktury zamiast klasy, jest deklarowanie funktora tuż przed użyciem go w wywołaniu funkcji i chcę zminimalizować składnię ze względu na przejrzystość. na przykład:
struct Compare { bool operator() { ... } };
std::sort(collection.begin(), collection.end(), Compare());
Z C ++ FAQ Lite :
Członkowie i podstawowe klasy struktury są domyślnie publiczne, podczas gdy w klasie domyślnie są prywatne. Uwaga: powinieneś jawnie uczynić swoje klasy podstawowe publicznymi, prywatnymi lub chronionymi, zamiast polegać na ustawieniach domyślnych.
struct i klasa są poza tym funkcjonalnie równoważne.
OK, dość tej piszczącej czystej techno. Emocjonalnie większość programistów dokonuje wyraźnego rozróżnienia między klasą a strukturą. Struktura po prostu wydaje się być otwartą stertą bitów z bardzo małą ilością możliwości enkapsulacji lub funkcjonalności. Klasa czuje się jak żywy i odpowiedzialny członek społeczeństwa z inteligentnymi usługami, silną barierą hermetyzacji i dobrze zdefiniowanym interfejsem. Ponieważ taka konotacja ma już większość ludzi, prawdopodobnie powinieneś użyć słowa kluczowego struct, jeśli masz klasę, która ma bardzo mało metod i dane publiczne (takie rzeczy istnieją w dobrze zaprojektowanych systemach!), Ale w przeciwnym razie prawdopodobnie powinieneś użyć tej klasy słowo kluczowe.
Jednym z miejsc, w którym struktura była dla mnie pomocna, jest system, który odbiera komunikaty o stałym formacie (np. Port szeregowy) z innego systemu. Możesz rzutować strumień bajtów na strukturę, która definiuje twoje pola, a następnie łatwo uzyskać do nich dostęp.
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);
}
Oczywiście jest to to samo, co zrobiłbyś w C, ale uważam, że narzut związany z dekodowaniem wiadomości do klasy zwykle nie jest tego wart.
operator >>
na klasie zamiast pisać processMessage
funkcję, dzięki czemu Twój C ++ będzie wyglądał bardziej jak poprawny C ++, a mniej jak C.
__packed__
struktury i mieć implementację ifdef obsługującą endian (musisz zmienić kolejność na komputerze, na którym endianess jest przeciwny do zewnętrznego źródła danych zapewnia). To nie jest ładne, ale zwykłem pakować / rozpakowywać rejestry zdalnych urządzeń peryferyjnych na platformach wbudowanych w przenośny sposób.
char
typ, który jest zwolniony z aliasingu. Jednak nadal istnieje problem, choć inny: rzutowanie char*
na inny typ, jeśli tak naprawdę nie było już żadnego obiektu tego drugiego typu, który został już zainicjowany pod tym adresem, jest UB, ponieważ narusza reguły życia. Afaik, nawet jeśli typ docelowy jest trywialnie konstruowalny, samo przydzielenie pamięci nie jest wystarczające, aby C ++ formalnie pozwalał na traktowanie tej pamięci jako tego typu.
Możesz użyć „struct” w C ++, jeśli piszesz bibliotekę, której wewnętrznymi elementami są C ++, ale API można wywoływać za pomocą kodu C lub C ++. Po prostu tworzysz pojedynczy nagłówek, który zawiera struktury i globalne funkcje API, które udostępniasz zarówno kodowi C, jak i C ++ w następujący sposób:
// 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
Następnie możesz napisać pasek funkcji () w pliku C ++ za pomocą kodu C ++ i ustawić go jako wywoływalny z C, a dwa światy mogą dzielić dane poprzez zadeklarowane struktury. Istnieją oczywiście inne zastrzeżenia dotyczące mieszania C i C ++, ale jest to uproszczony przykład.
Jak wszyscy mówią, jedyną prawdziwą różnicą jest domyślny dostęp. Ale szczególnie używam struct, gdy nie chcę żadnego enkapsulacji za pomocą prostej klasy danych, nawet jeśli zaimplementuję jakieś metody pomocnicze. Na przykład, gdy potrzebuję czegoś takiego:
struct myvec {
int x;
int y;
int z;
int length() {return x+y+z;}
};
Aby odpowiedzieć na moje pytanie (bezwstydnie), jak już wspomniano, uprawnienia dostępu są jedyną różnicą między nimi w C ++.
Zwykle używam struktury tylko do przechowywania danych. Pozwolę mu uzyskać kilka funkcji pomocniczych, jeśli ułatwi to pracę z danymi. Jednak gdy tylko dane wymagają kontroli przepływu (tj. Pobierające / ustawiające, które utrzymują lub chronią stan wewnętrzny) lub zaczynają uzyskiwać jakąkolwiek większą funkcjonalność (zasadniczo bardziej obiektową), zostaną „uaktualnione” do klasy, aby lepiej komunikować zamiary.
Struktury ( POD , bardziej ogólnie) są przydatne, gdy zapewniasz interfejs kompatybilny z C z implementacją C ++, ponieważ są one przenośne ponad granicami języków i formatami linkerów.
Jeśli to nie dotyczy ciebie, to przypuszczam, że użycie „struct” zamiast „class” jest dobrym komunikatorem intencji (jak wspomniano powyżej @ ZeroSignal). Struktury mają również bardziej przewidywalną semantykę kopiowania, więc są przydatne w przypadku danych, które zamierzasz zapisać na nośniku zewnętrznym lub przesłać przewodowo.
Struktury są również przydatne do różnych zadań metaprogramowania, takich jak szablony cech, które po prostu ujawniają kilka zależnych typów typów:
template <typename T> struct type_traits {
typedef T type;
typedef T::iterator_type iterator_type;
...
};
... Ale tak naprawdę to korzysta z domyślnego poziomu ochrony structa, który jest publiczny ...
W przypadku C ++ naprawdę nie ma dużej różnicy między strukturami a klasami. Główną różnicą funkcjonalną jest to, że członkowie struktury są domyślnie publiczni, podczas gdy domyślnie są prywatni w klasach. W przeciwnym razie, jeśli chodzi o język, są one równoważne.
To powiedziawszy, zwykle używam struktur w C ++, tak jak robię to w C #, podobnie jak powiedział Brian. Struktury są prostymi kontenerami danych, podczas gdy klasy są używane dla obiektów, które muszą oddziaływać na dane oprócz tylko ich trzymania.
Są prawie takie same. Dzięki magii C ++, struct może przechowywać funkcje, używać dziedziczenia, tworzone przy użyciu „new” i tak dalej jak klasa
Jedyną różnicą funkcjonalną jest to, że klasa zaczyna się od prywatnych praw dostępu, a struct zaczyna się od public. Jest to zachowanie zgodności wstecznej z C.
W praktyce zawsze używałem struktur jako posiadaczy danych, a klas jako obiektów.
Jak zauważyli inni
Istnieje wyraźne zalecenie dotyczące tego, kiedy stosować Stroustrup / Sutter:
Pamiętaj jednak, że nie jest mądre przekazywanie dalej czegoś. jako class ( class X;
) i zdefiniuj go jako struct ( struct X { ... }
). Może działać na niektórych linkerach (np. G ++) i może zawieść na innych (np. MSVC), więc znajdziesz się w piekle programisty.
class Foo; struct Foo { void bar() {} }; int main() { Foo().bar(); }
nie tylko kompiluje się i działa z MSVC 2017, ale nawet tworzy wyraźne ostrzeżenie, które Foo
zostało zadeklarowane jako struct
zdefiniowane jako class
. Ale pamiętam też wyraźnie, że znalezienie tego głupiego robaka kosztowało nasz zespół pół dnia. Nie jestem pewien, jakiej wersji MSVC używaliśmy wtedy.
class
lub struct
na przednim deklaracji, a dwa są swobodnie wymienialne na standardzie (choć wiadomo, że VS ostrzega, zawsze zakłada się, że właśnie w celu uniknięcia widocznych błędów programista). Coś tu nie pachnie. Czy na pewno nie był to błąd naruszenia ODR?
struct
Forward na- class
Forward, problemy zniknęły. Na dzień dzisiejszy też wydaje mi się to dziwne. Byłbym zadowolony, gdybyś mógł rzucić na to trochę światła.
Członkowie klasy są domyślnie prywatni.
class test_one {
int main_one();
};
Jest równa
class test_one {
private:
int main_one();
};
Więc jeśli spróbujesz
int two = one.main_one();
Otrzymamy błąd: main_one is private
ponieważ nie jest dostępny. Możemy go rozwiązać, inicjując go, określając go jako publiczny, tj
class test_one {
public:
int main_one();
};
Struktura to klasa, w której członkowie są domyślnie publiczni.
struct test_one {
int main_one;
};
Środki main_one
są prywatne tj
class test_one {
public:
int main_one;
};
Używam struktur do struktur danych, w których członkowie mogą przyjmować dowolną wartość, w ten sposób jest łatwiej.
Zaletą struct
przez class
to, że uratować jedną linię kodu, jeśli przylegającą do „pierwszych członków publicznych, następnie prywatna”. W tym świetle znajduję słowo kluczoweclass
bezużyteczne.
Oto kolejny powód używania tylko struct
i nigdy class
. Niektóre wytyczne dotyczące stylu kodu dla C ++ sugerują używanie małych liter w makrach funkcyjnych, uzasadnieniem jest to, że kiedy makro jest konwertowane na funkcję wbudowaną, nazwa nie powinna wymagać zmiany. To samo tutaj. Masz swoją ładną strukturę w stylu C i pewnego dnia dowiadujesz się, że musisz dodać konstruktor lub jakąś wygodną metodę. Czy zmienisz to na class
? Wszędzie?
Rozróżnianie struct
s oraz class
es jest po prostu zbyt wiele kłopotów, dostając w zasadzie robi to, co powinniśmy robić - programowanie. Podobnie jak wiele problemów C ++, wynika on z silnego pragnienia wstecznej kompatybilności.
class
? Czy uważasz, że klasa zdefiniowana za pomocą struct
słowa kluczowego nie może mieć funkcji członka ani konstruktora?
joe()
musi być zdefiniowana za pomocą class
słowa kluczowego? Każda klasa z co najmniej 4 int
członkami musi być zdefiniowana za pomocą struct
słowa kluczowego?
struct
, agregaty metodami są zdefiniowane za pomocą class
”. Za dużo kłopotów.
są takie same z różnymi ustawieniami domyślnymi (domyślnie prywatne class
i publiczne dla struct
), więc teoretycznie są one całkowicie wymienne.
więc jeśli chcę tylko spakować jakieś informacje, aby się poruszać, używam struktury, nawet jeśli podam tam kilka metod (ale nie wiele). Jeśli jest to w większości nieprzejrzyste, gdzie głównym zastosowaniem byłyby metody, a nie bezpośrednio członkowie danych, używam pełnej klasy.
Zarówno struct
i class
są takie same pod maską choć z różnych domyślnych co do widoczności, struct
domyślnie jest publiczny i class
domyślnie jest prywatny. Możesz zmienić jedno z nich, używając odpowiednio private
ipublic
. Obie pozwalają na dziedziczenie, metody, konstruktory, destruktory i wszystkie inne zalety języka zorientowanego obiektowo.
Jednak jedna ogromna różnica między nimi polega na tym, że struct
słowo kluczowe jest obsługiwane w języku C, podczas gdy class
nie. Oznacza to, że można używać struct
w include pliku, który można #include
w każdej C ++ lub C tak długo, jak struct
to zwykły C styl struct
i wszystko w include plik jest kompatybilny z C, to znaczy nie C ++ konkretne słowa kluczowe, takie jak private
, public
nie metody, brak dziedziczenia itp. itd. itd.
Styl AC struct
może być używany z innymi interfejsami, które obsługują styl C struct
do przenoszenia danych tam iz powrotem przez interfejs.
Styl AC struct
to rodzaj szablonu (nie szablon C ++, ale raczej wzór lub szablon), który opisuje układ obszaru pamięci. Z biegiem lat interfejsy użytkowej z C i C wtyczek (tu patrzy na ciebie Java i Python i Visual Basic) zostały stworzone z których niektóre prace z klasą C struct
.
Technicznie oba są takie same w C ++ - na przykład istnieje możliwość przeciążenia operatorów przez strukturę itp.
Jednak :
Używam struktur, gdy chcę przekazywać informacje wielu typów jednocześnie. Korzystam z klas, gdy mam do czynienia z „funkcjonalnym” obiektem.
Mam nadzieję, że to pomoże.
#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;
};
Na przykład zwracam tutaj ucznia strukturalnego metodami get ... () tutaj - baw się dobrze.
Kiedy zdecydujesz się użyć struct, a kiedy klasy w C ++?
Używam, struct
kiedy definiuję functors
i POD
. W przeciwnym razie używam 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<>
nie jest po prostu przestarzała, c ++ 17 nawet ją usuwa.
Wszyscy członkowie klasy są domyślnie prywatni, a wszyscy członkowie struktury są domyślnie publiczni. Klasa ma domyślne bazy prywatne, a Struct ma domyślne bazy publiczne. Struct w przypadku C nie może mieć funkcji składowych, przy czym tak jak w przypadku C ++ możemy dodawać funkcje składowe do struktury. Poza tymi różnicami nie znajduję w nich nic zaskakującego.
Używam struct tylko wtedy, gdy muszę przechowywać niektóre dane bez powiązanych z nim funkcji członkowskich (aby operować na danych członka) i uzyskać bezpośredni dostęp do zmiennych danych.
Np .: Odczytywanie / zapisywanie danych z plików i strumieni gniazd itp. Przekazywanie argumentów funkcji w strukturze, w której argumentów funkcji jest zbyt wiele, a składnia funkcji wygląda na zbyt długą.
Technicznie nie ma dużej różnicy między klasą a strukturą, z wyjątkiem domyślnej dostępności. Ponadto zależy od stylu programowania, w jaki sposób go używasz.
Pomyślałem, że Structions ma być strukturą danych (jak tablica informacji zawierająca wiele danych), a klasy były przeznaczone do pakowania kodu (podobnie jak zbiory podprogramów i funkcji).
:(
Nigdy nie używam „struct” w C ++.
Nie mogę sobie wyobrazić scenariusza, w którym użyłbyś struktury, gdy chcesz członków prywatnych, chyba że celowo próbujesz być mylący.
Wydaje się, że użycie struktur jest bardziej składniowym wskazaniem, w jaki sposób dane będą wykorzystywane, ale wolałbym po prostu stworzyć klasę i spróbować wyrazić to wyraźnie w nazwie klasy lub poprzez komentarze.
Na przykład
class PublicInputData {
//data members
};
struct
że członkowie klasy będą domyślnie publiczni, nie byłoby już jednoznaczne?