W jakich scenariuszach lepiej jest używać structvs classw C ++?
W jakich scenariuszach lepiej jest używać structvs classw C ++?
Odpowiedzi:
Różnice między classai structw C ++ polegają na tym, że struktury mają domyślne publicelementy i bazy, a klasy mają domyślne privateelementy i bazy. Obie klasy i kodowanym może mieć mieszankę public, protectediprivate 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 privatedanych z danymi i funkcjami składowymi.
Jak wszyscy zauważają, w rzeczywistości istnieją tylko dwie rzeczywiste różnice językowe:
structdomyślnie dostęp publiczny i classdomyślny dostęp prywatny.structdomyślnie przyjmuje publicdziedziczenie i classdomyślnie privatedziedziczenie. (Jak na ironię, podobnie jak w przypadku wielu rzeczy w C ++, domyślnie jest to wstecz: publicdziedziczenie jest zdecydowanie bardziej powszechnym wyborem, ale ludzie rzadko deklarują, structże oszczędzają na wpisaniu publicsł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 structs dla typów POD, a jeśli zamierzają w ogóle dodać jakiekolwiek metody, używają classes. 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 ++? )
structlub classnie 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 classi structdeklarują 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ę structsł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ć classsłowa kluczowego dla klas z funkcjami i privatedanymi 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ą classlub 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.
Fooi Barnadal 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ć processMessagefunkcję, 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.
chartyp, 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 Foozostało zadeklarowane jako structzdefiniowane 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.
classlub structna 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?
structForward na- classForward, 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 privateponieważ 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_onesą 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ą structprzez classto, ż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 structi 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 structs oraz classes 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ą structsłowa kluczowego nie może mieć funkcji członka ani konstruktora?
joe()musi być zdefiniowana za pomocą classsłowa kluczowego? Każda klasa z co najmniej 4 intczłonkami musi być zdefiniowana za pomocą structsł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 classi 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 structi classsą takie same pod maską choć z różnych domyślnych co do widoczności, structdomyślnie jest publiczny i classdomyślnie jest prywatny. Możesz zmienić jedno z nich, używając odpowiednio privateipublic . 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 structsłowo kluczowe jest obsługiwane w języku C, podczas gdy classnie. Oznacza to, że można używać structw include pliku, który można #includew każdej C ++ lub C tak długo, jak structto zwykły C styl structi wszystko w include plik jest kompatybilny z C, to znaczy nie C ++ konkretne słowa kluczowe, takie jak private, publicnie metody, brak dziedziczenia itp. itd. itd.
Styl AC structmoże być używany z innymi interfejsami, które obsługują styl C structdo przenoszenia danych tam iz powrotem przez interfejs.
Styl AC structto 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, structkiedy definiuję functorsi 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?