W programowaniu jest wiele przypadków, w których potrzebujemy więcej niż jednej zmiennej, aby przedstawić coś interesującego. Jak omawialiśmy we wstępie do poprzedniego rozdziału (12.1 — Wprowadzenie do złożonych typów danych), ułamek ma licznik i mianownik połączone w jeden obiekt matematyczny.
Alternatywnie, powiedzmy, że chcemy napisać program, w którym będziemy przechowywać informacje o pracownikach firmy. Możemy być zainteresowani śledzeniem atrybutów, takich jak imię i nazwisko pracownika, stanowisko, wiek, identyfikator pracownika, identyfikator menedżera, wynagrodzenie, urodziny, data zatrudnienia itp.
Gdybyśmy mieli użyć niezależnych zmiennych do śledzenia wszystkich tych informacji, mogłoby to wyglądać mniej więcej tak:
std::string name;
std::string title;
int age;
int id;
int managerId;
double wage;
int birthdayYear;
int birthdayMonth;
int birthdayDay;
int hireYear;
int hireMonth;
int hireDay;Jednak istnieje wiele problemów z tym podejściem. Po pierwsze, nie jest od razu jasne, czy te zmienne są rzeczywiście powiązane, czy nie (trzeba przeczytać komentarze lub zobaczyć, jak są używane w kontekście). Po drugie, istnieje teraz 12 zmiennych, którymi należy zarządzać. Gdybyśmy chcieli przekazać tego pracownika do funkcji, musielibyśmy przekazać 12 argumentów (w odpowiedniej kolejności), co spowodowałoby bałagan w naszych prototypach funkcji i wywołaniach funkcji. A skoro funkcja może zwrócić tylko jedną wartość, jak w ogóle mogłaby zwrócić pracownika?
A gdybyśmy chcieli mieć więcej niż jednego pracownika, musielibyśmy zdefiniować 12 dodatkowych zmiennych dla każdego dodatkowego pracownika (z których każdy wymagałby unikalnej nazwy)! To najwyraźniej w ogóle nie ma skali. Tak naprawdę potrzebujemy sposobu na zorganizowanie wszystkich powiązanych ze sobą fragmentów danych, aby ułatwić zarządzanie nimi.
Na szczęście w C++ dostępne są dwa typy złożone zaprojektowane z myślą o rozwiązywaniu takich problemów: struktury (które teraz przedstawimy) i klasy (które omówimy wkrótce). A struct (skrót od structure) to zdefiniowany przez program typ danych (13.1 -- Wprowadzenie do typów zdefiniowanych przez program (zdefiniowanych przez użytkownika)), który pozwala nam połączyć wiele zmiennych w jeden typ. Jak wkrótce się przekonasz, znacznie upraszcza to zarządzanie powiązanymi zestawami zmiennych!
Przypomnienie
Struktura jest typem klasy (podobnie jak klasy i związki). W związku z tym wszystko, co dotyczy typów klas, dotyczy również struktur.
Definiowanie struktur
Ponieważ struktury są typem zdefiniowanym w programie, najpierw musimy powiedzieć kompilatorowi, jak wygląda nasz typ struktury, zanim będziemy mogli go używać. Oto przykład definicji struktury dla uproszczonego pracownika:
struct Employee
{
int id {};
int age {};
double wage {};
};Klasa struct słowo kluczowe służy do poinformowania kompilatora, że definiujemy strukturę, której nadaliśmy nazwę Employee (ponieważ typy zdefiniowane w programie mają zazwyczaj nazwy rozpoczynające się z dużej litery).
Następnie w nawiasach klamrowych definiujemy zmienne, które będzie zawierać każdy obiekt Pracownik. W tym przykładzie każda utworzona przez nas Employee będzie miała 3 zmienne: an int id, an int age i a double wage. Zmienne wchodzące w skład struktury nazywane są elementami danych (lub zmiennymi składowymi).
Wskazówka
W języku potocznym member to jednostka należąca do grupy. Na przykład możesz być członkiem drużyny koszykówki, a twoja siostra może być członkinią chóru.
W C++ instrukcja member to zmienna, funkcja lub typ należący do struktury (lub klasy). Wszystkie elementy muszą być zadeklarowane w definicji struktury (lub klasy).
Będziemy często używać terminu member , więc pamiętaj, co on oznacza.
Podobnie jak używamy pustego zestawu nawiasów klamrowych do inicjowania wartości (1.4 — Przypisywanie zmiennych i inicjalizacja) normalnych zmiennych, puste nawiasy klamrowe po każdej zmiennej składowej zapewniają że zmienne składowe wewnątrz naszego Employee są wartością inicjowaną, gdy Employee został utworzony. Porozmawiamy o tym więcej, gdy w kilku lekcjach omówimy domyślną inicjalizację elementu członkowskiego (13.9 — Domyślna inicjalizacja elementu członkowskiego).
Na koniec definicję typu zakończymy średnikiem.
Dla przypomnienia, Employee to tylko definicja typu — w tym momencie nie są tworzone żadne obiekty.
Definiowanie obiektów strukturalnych
Aby użyć typu Employee , po prostu definiujemy zmienną type Employee:
Employee joe {}; // Employee is the type, joe is the variable nameDefiniuje zmienną typu Employee nazwany joe. Po wykonaniu kodu tworzona jest instancja obiektu Employee zawierającego 3 elementy danych. Puste nawiasy klamrowe zapewniają inicjalizację wartości obiektu.
Tak jak w przypadku każdego innego typu, możliwe jest zdefiniowanie wielu zmiennych tego samego typu struktury:
Employee joe {}; // create an Employee struct for Joe
Employee frank {}; // create an Employee struct for FrankCzłonkowie dostępu
Rozważ następujący przykład:
struct Employee
{
int id {};
int age {};
double wage {};
};
int main()
{
Employee joe {};
return 0;
}W powyższym przykładzie nazwa joe odnosi się do całego obiektu struktury (który zawiera zmienne składowe). Aby uzyskać dostęp do określonej zmiennej składowej, używamy operatora wyboru elementu (operator.) pomiędzy nazwą zmiennej struktury a nazwą składową. Na przykład, aby uzyskać dostęp do elementu wiek Joego, użylibyśmy joe.age.
Zmienne składowe Struct działają tak samo jak zwykłe zmienne, więc można na nich wykonywać normalne operacje, w tym przypisywanie, arytmetykę, porównania itp....
#include <iostream>
struct Employee
{
int id {};
int age {};
double wage {};
};
int main()
{
Employee joe {};
joe.age = 32; // use member selection operator (.) to select the age member of variable joe
std::cout << joe.age << '\n'; // print joe's age
return 0;
}Wypisuje:
32
Jedną z największych zalet struktur jest to, że dla każdej zmiennej struktury wystarczy utworzyć tylko jedną nową nazwę (nazwy elementów są stałe w ramach definicji typu struktury). W poniższym przykładzie tworzymy dwa Employee obiekty: joe i frank.
#include <iostream>
struct Employee
{
int id {};
int age {};
double wage {};
};
int main()
{
Employee joe {};
joe.id = 14;
joe.age = 32;
joe.wage = 60000.0;
Employee frank {};
frank.id = 15;
frank.age = 28;
frank.wage = 45000.0;
int totalAge { joe.age + frank.age };
std::cout << "Joe and Frank have lived " << totalAge << " total years\n";
if (joe.wage > frank.wage)
std::cout << "Joe makes more than Frank\n";
else if (joe.wage < frank.wage)
std::cout << "Joe makes less than Frank\n";
else
std::cout << "Joe and Frank make the same amount\n";
// Frank got a promotion
frank.wage += 5000.0;
// Today is Joe's birthday
++joe.age; // use pre-increment to increment Joe's age by 1
return 0;
}W powyższym przykładzie bardzo łatwo jest stwierdzić, które zmienne składowe należą do Joe, a które do Franka. Zapewnia to znacznie wyższy poziom organizacji niż pojedyncze zmienne. Co więcej, ponieważ elementy Joe i Franka mają te same nazwy, zapewnia to spójność, gdy masz wiele zmiennych tego samego typu struktury.
Będziemy kontynuować eksplorację struktur w następnej lekcji, w tym przyjrzymy się, jak je inicjować.

