Przejdź do głównej zawartości

Typ boolowski

Typ bool

Jeśli pamiętasz z lekcji o zmiennych, jednym z podstawowych typów jest bool. Typ ten reprezentuje wartość logiczną (wartość boolowską), która ma tylko jedną wartość true lub false.

Wyrażenia boolowskie, o których dowiedzieliśmy się na początku tej lekcji o warunkach, ewaluują się do wartości logicznej (boolowskiej). Możemy więc stworzyć zmienne, które są wynikami takich wyrażeń logicznych, a następnie dalej używać tych zmiennych bool w warunkach instrukcji if.

W C++ istnieją dwie wbudowane wartości logiczne - true i false. Można ich użyć wszędzie tam, gdzie oczekiwany jest typ bool lub wyrażenie boolowskie. Dla przykładu:

Literały boolowskie
bool var1 = true;
bool var2 = false;

Są też ciekawsze rzeczy, które możemy zrobić ze zmiennymi bool. Każde wyrażenie boolean można przypisać do zmiennej. Połączenie tego z instrukcjami if może w niektórych przypadkach skrócić kod i uczynić go bardziej czytelnym.

Używanie zmiennych boolowskich do określania pogody
std::string name;

std::cout << "Enter your first name: ";
std::cin >> name;

// Użytkownik jest szczęśliwy, jeśli jego imię ma więcej niż 5 znaków
bool is_lucky = name.size() > 5;

// Spróbuj pozmieniać te wartości i zobacz co się stanie!
bool is_tuesday = true;
bool is_cloudy = false;

std::string weather = "sunny";

if (not is_tuesday and is_cloudy) {
weather = "raining";
} else if (is_tuesday) {
if (is_cloudy) {
weather = "overcast";
} else if (not is_lucky) {
weather = "downpouring";
}
}

std::cout << "It is currently " << weather << " in your location!";

Wcześniej wprowadzone operatory logiczne mogą zostać użyte do stworzenia nowych zmiennych boolowskich:

Używanie operatorów logicznych na boolach
bool is_precipitating = weather == "raining" or weather == "downpouring";
bool is_rainbow_made = is_precipitating and not is_cloudy;
bool is_boring_day = not is_rainbow_made;

Wczytywanie/Wypisywanie typów boolowskich

Jeśli próbowałeś sam eksperymentować z typem bool, mogłeś zauważyć, że wypisanie zmiennej lub wyrażenia tego typu nie wyświetla true czy false, a 1 lub 0. Jest to domyślne zachowanie w C++, które jest związane z następną sekcją.

Możesz zmienić to zachowanie w prosty sposób zmieniając jedno z domyślnych ustawień std::cout. Po prostu "wypisz" flagę std::boolalpha za pomocą std::cout. Spowoduje to, że każde przyszłe wyrażenie logiczne lub zmienna typu bool zostanie wypisana w postaci true/false, zamiast 1/0.

Dołączenie odpowiedniego nagłówka

Upewniej się, że dołączyłeś nagłówek <iomanip> (#include <iomanip>), aby móc użyć std::boolalpha.

Wypisywanie true/false
std::cout << true << " " << false << "\n";
std::cout << std::boolalpha;
std::cout << true << " " << false << "\n";
Wynik
1 0
true false

Tak samo std::cin domyślnie akceptuje tylko 0 lub 1 przy wprowadzaniu do zmiennej bool. To zachowanie może być również zmienione przez "wprowadzenie" do flagi std::boolalpha. W poniższym przykładzie, użytkownik najpierw wprowadzi 0, co reprezentuje false. Następnie, wprowadzi true po zastosowaniu ustawienia std::boolalpha.

Wprowadzanie true/false
bool var;

std::cout << "Integral form: ";
std::cin >> var;

std::cin >> std::boolalpha;

std::cout << "Alphanumeric form: ";
std::cin >> var;
Input/Output
Integral form: 1
Alphanumeric form: true

Jako ćwiczenie, spróbuj zmodyfikować nasz program pogodowy, tak, aby przyjmował true/false, zamiast 1/0.

Ciekawostka

Nazwa "boolalpha" pochodzi ze złączenia słów boolean i alphanumeric (ang.: alfanumeryczny)

Konwersja pomiędzy int a bool

C++ posiada kolejne, dość denerwujące, zachowanie, które powoduje, że liczby i typy boolowskie mogą się niejawnie konwertować pomiędzy sobą. Wartość boolowska false odpowiada liczbie o wartośći 0, a true wartości 1. Tak samo liczba o wartości 0 odpowiada wartości boolowskiej false, a każda inna od 0 odpowiada wartości true.

Przykład konwersji pomiędzy liczbami a boolami
int x = true; // x to 1
int y = false; // y to 0

bool a = 1; // a to true
bool b = 25; // b to true
bool c = -194; // c to true
bool d = 0; // d to false

Mimo, że to zachowanie może się wydawać przydatne, czasem może się zdarzyć, że konwersja wydarzy się wtedy, kiedy nie jest chciana. Z tego powodu, jeśli chcesz intencjonalnie spowodować konwersję pomiędzy int (lub każdym innym typem całkowitoliczbowym), a bool użyć casta.

Castowanie pomiędzy int a bool
int x = static_cast<int>(true); // Nowoczesny styl castowania
int y = (int) false; // Castowanie w stylu C

bool a = static_cast<bool>(1);
bool b = (bool) 0;

Są dwa sposoby na jakie możemy przeprowadzić takie castowanie w C++ - castowanie nazwane, a konkretnie static_cast (nowoczesny sposób), lub castowanie w stylu C.

Różnice między nimi poznasz w kursie dla średniozaawansowanych. Na razie wiedz tylko, że, w przypadku konwersji pomiędzy int, a bool, obie opcje są równoważne. Jednak w nowoczesnym C++ generalnie preferowane jest używanie static_cast.

Niechciane konwersje

Niechciane konwersje mogą powodować problemy tak, gdzie najmniej się ich spodziewasz. Jednym z przykładów jest problem, który omówiliśmy w złożone warunki logiczne. Normalnie, jeśli chcemy połączyć dwa wyrażenia logiczne, używamy do tego operatorów logicznych:

if (x > 10 && x < 25) { ... }

Może Cię kusić, aby przepisać ten warunek jako 10 < x < 25. To spowoduje, że program będzie się zachowywać niepoprawnie, ponieważ to wyrażenie będzie zawsze prawdziwe. Dzieje się tak, ponieważ zachodzi tutaj ukryta konwersja z bool na int. To wyrażenie jest interpretowane w taki sposób: (10 < x) < 25.

Zobaczmy więc w jaki sposób to wyrażenie zawsze ewaluuje się do true odnosząc się do naszej tabeli priorytetów operatorów:

Niepoprawne łączenie warunków z x = 15
10 < x < 25    // Początkowe wyrażenie
10 < 15 < 25 // Podstawiamy x
(10 < 15) < 25 // Kolejność operatorów
(true) < 25 // Ewaluujemy podwyrażenie
1 < 25 // Konwersja z bool na int
true // Ewaluujemy wyrażenie
Niepoprawne łączenie warunków z x = 7
10 < x < 25   // Początkowe wyrażenie
10 < 7 < 25 // Podstawiamy x
(10 < 7) < 25 // Kolejność operatorów
(false) < 25 // Ewaluujemy podwyrażenie
0 < 25 // Konwersja z bool na int
true // Ewaluujemy wyrażenie

Ten sam problem może wystąpić również w innych, podobnych scenariuszach. Na przykład, podczas sprawdzania, czy pojedyncza zmienna jest jedną z wielu możliwości, poprawnym sposobem byłoby x == 5 || x == 10 || x == 15. Kusząca opcja x == 5 || 10 || 15 nie zadziała z podobnego powodu jak wyżej - zawsze będzie to prawda. Zobaczmy dlaczego:

Niepoprawne łączenie warunków z x = 5
x == 5 || 10 || 15     // Początkowe wyrażenie
5 == 5 || 10 || 15 // Podstawiamy x
((5 == 5) || 10) || 15 // Kolejność operatorów
((true) || 10) || 15 // Ewaluujemy podwyrażenie
(true || true) || 15 // Konwersja z int na bool
true || 15 // Ewaluujemy podwyrażenie
true || true // Konwersja z int na bool
true // Ewaluujemy wyrażenie
Niepoprawne łączenie warunków z x = 7
x == 5 || 10 || 15     // Początkowe wyrażenie
7 == 5 || 10 || 15 // Podstawiamy x
((7 == 5) || 10) || 15 // Kolejność operatorów
((false) || 10) || 15 // Ewaluujemy podwyrażenie
(false || true) || 15 // Konwersja z int na bool
true || 15 // Ewaluujemy podwyrażenie
true || true // Konwersja z int na bool
true // Ewaluujemy wyrażenie

Konkluzja

Podsumowaując, nauczyliśmy się:

To była długa podróż, ale umiejętności, które zebrałeś w tej lekcji są bardzo ważne dla przyszłej drogi. Przeczytaj kilka razy koncepcje przedstawione w tej lekcji, ponieważ podstawy wyrażeń logicznych i instrukcji warunkowych są bardzo ważną umiejętnością.

Typ boolowski

Typ bool

Jeśli pamiętasz z lekcji o zmiennych, jednym z podstawowych typów jest bool. Typ ten reprezentuje wartość logiczną (wartość boolowską), która ma tylko jedną wartość true lub false.

Wyrażenia boolowskie, o których dowiedzieliśmy się na początku tej lekcji o warunkach, ewaluują się do wartości logicznej (boolowskiej). Możemy więc stworzyć zmienne, które są wynikami takich wyrażeń logicznych, a następnie dalej używać tych zmiennych bool w warunkach instrukcji if.

W C++ istnieją dwie wbudowane wartości logiczne - true i false. Można ich użyć wszędzie tam, gdzie oczekiwany jest typ bool lub wyrażenie boolowskie. Dla przykładu:

Literały boolowskie
bool var1 = true;
bool var2 = false;

Są też ciekawsze rzeczy, które możemy zrobić ze zmiennymi bool. Każde wyrażenie boolean można przypisać do zmiennej. Połączenie tego z instrukcjami if może w niektórych przypadkach skrócić kod i uczynić go bardziej czytelnym.

Używanie zmiennych boolowskich do określania pogody
std::string name;

std::cout << "Enter your first name: ";
std::cin >> name;

// Użytkownik jest szczęśliwy, jeśli jego imię ma więcej niż 5 znaków
bool is_lucky = name.size() > 5;

// Spróbuj pozmieniać te wartości i zobacz co się stanie!
bool is_tuesday = true;
bool is_cloudy = false;

std::string weather = "sunny";

if (not is_tuesday and is_cloudy) {
weather = "raining";
} else if (is_tuesday) {
if (is_cloudy) {
weather = "overcast";
} else if (not is_lucky) {
weather = "downpouring";
}
}

std::cout << "It is currently " << weather << " in your location!";

Wcześniej wprowadzone operatory logiczne mogą zostać użyte do stworzenia nowych zmiennych boolowskich:

Używanie operatorów logicznych na boolach
bool is_precipitating = weather == "raining" or weather == "downpouring";
bool is_rainbow_made = is_precipitating and not is_cloudy;
bool is_boring_day = not is_rainbow_made;

Wczytywanie/Wypisywanie typów boolowskich

Jeśli próbowałeś sam eksperymentować z typem bool, mogłeś zauważyć, że wypisanie zmiennej lub wyrażenia tego typu nie wyświetla true czy false, a 1 lub 0. Jest to domyślne zachowanie w C++, które jest związane z następną sekcją.

Możesz zmienić to zachowanie w prosty sposób zmieniając jedno z domyślnych ustawień std::cout. Po prostu "wypisz" flagę std::boolalpha za pomocą std::cout. Spowoduje to, że każde przyszłe wyrażenie logiczne lub zmienna typu bool zostanie wypisana w postaci true/false, zamiast 1/0.

Dołączenie odpowiedniego nagłówka

Upewniej się, że dołączyłeś nagłówek <iomanip> (#include <iomanip>), aby móc użyć std::boolalpha.

Wypisywanie true/false
std::cout << true << " " << false << "\n";
std::cout << std::boolalpha;
std::cout << true << " " << false << "\n";
Wynik
1 0
true false

Tak samo std::cin domyślnie akceptuje tylko 0 lub 1 przy wprowadzaniu do zmiennej bool. To zachowanie może być również zmienione przez "wprowadzenie" do flagi std::boolalpha. W poniższym przykładzie, użytkownik najpierw wprowadzi 0, co reprezentuje false. Następnie, wprowadzi true po zastosowaniu ustawienia std::boolalpha.

Wprowadzanie true/false
bool var;

std::cout << "Integral form: ";
std::cin >> var;

std::cin >> std::boolalpha;

std::cout << "Alphanumeric form: ";
std::cin >> var;
Input/Output
Integral form: 1
Alphanumeric form: true

Jako ćwiczenie, spróbuj zmodyfikować nasz program pogodowy, tak, aby przyjmował true/false, zamiast 1/0.

Ciekawostka

Nazwa "boolalpha" pochodzi ze złączenia słów boolean i alphanumeric (ang.: alfanumeryczny)

Konwersja pomiędzy int a bool

C++ posiada kolejne, dość denerwujące, zachowanie, które powoduje, że liczby i typy boolowskie mogą się niejawnie konwertować pomiędzy sobą. Wartość boolowska false odpowiada liczbie o wartośći 0, a true wartości 1. Tak samo liczba o wartości 0 odpowiada wartości boolowskiej false, a każda inna od 0 odpowiada wartości true.

Przykład konwersji pomiędzy liczbami a boolami
int x = true; // x to 1
int y = false; // y to 0

bool a = 1; // a to true
bool b = 25; // b to true
bool c = -194; // c to true
bool d = 0; // d to false

Mimo, że to zachowanie może się wydawać przydatne, czasem może się zdarzyć, że konwersja wydarzy się wtedy, kiedy nie jest chciana. Z tego powodu, jeśli chcesz intencjonalnie spowodować konwersję pomiędzy int (lub każdym innym typem całkowitoliczbowym), a bool użyć casta.

Castowanie pomiędzy int a bool
int x = static_cast<int>(true); // Nowoczesny styl castowania
int y = (int) false; // Castowanie w stylu C

bool a = static_cast<bool>(1);
bool b = (bool) 0;

Są dwa sposoby na jakie możemy przeprowadzić takie castowanie w C++ - castowanie nazwane, a konkretnie static_cast (nowoczesny sposób), lub castowanie w stylu C.

Różnice między nimi poznasz w kursie dla średniozaawansowanych. Na razie wiedz tylko, że, w przypadku konwersji pomiędzy int, a bool, obie opcje są równoważne. Jednak w nowoczesnym C++ generalnie preferowane jest używanie static_cast.

Niechciane konwersje

Niechciane konwersje mogą powodować problemy tak, gdzie najmniej się ich spodziewasz. Jednym z przykładów jest problem, który omówiliśmy w złożone warunki logiczne. Normalnie, jeśli chcemy połączyć dwa wyrażenia logiczne, używamy do tego operatorów logicznych:

if (x > 10 && x < 25) { ... }

Może Cię kusić, aby przepisać ten warunek jako 10 < x < 25. To spowoduje, że program będzie się zachowywać niepoprawnie, ponieważ to wyrażenie będzie zawsze prawdziwe. Dzieje się tak, ponieważ zachodzi tutaj ukryta konwersja z bool na int. To wyrażenie jest interpretowane w taki sposób: (10 < x) < 25.

Zobaczmy więc w jaki sposób to wyrażenie zawsze ewaluuje się do true odnosząc się do naszej tabeli priorytetów operatorów:

Niepoprawne łączenie warunków z x = 15
10 < x < 25    // Początkowe wyrażenie
10 < 15 < 25 // Podstawiamy x
(10 < 15) < 25 // Kolejność operatorów
(true) < 25 // Ewaluujemy podwyrażenie
1 < 25 // Konwersja z bool na int
true // Ewaluujemy wyrażenie
Niepoprawne łączenie warunków z x = 7
10 < x < 25   // Początkowe wyrażenie
10 < 7 < 25 // Podstawiamy x
(10 < 7) < 25 // Kolejność operatorów
(false) < 25 // Ewaluujemy podwyrażenie
0 < 25 // Konwersja z bool na int
true // Ewaluujemy wyrażenie

Ten sam problem może wystąpić również w innych, podobnych scenariuszach. Na przykład, podczas sprawdzania, czy pojedyncza zmienna jest jedną z wielu możliwości, poprawnym sposobem byłoby x == 5 || x == 10 || x == 15. Kusząca opcja x == 5 || 10 || 15 nie zadziała z podobnego powodu jak wyżej - zawsze będzie to prawda. Zobaczmy dlaczego:

Niepoprawne łączenie warunków z x = 5
x == 5 || 10 || 15     // Początkowe wyrażenie
5 == 5 || 10 || 15 // Podstawiamy x
((5 == 5) || 10) || 15 // Kolejność operatorów
((true) || 10) || 15 // Ewaluujemy podwyrażenie
(true || true) || 15 // Konwersja z int na bool
true || 15 // Ewaluujemy podwyrażenie
true || true // Konwersja z int na bool
true // Ewaluujemy wyrażenie
Niepoprawne łączenie warunków z x = 7
x == 5 || 10 || 15     // Początkowe wyrażenie
7 == 5 || 10 || 15 // Podstawiamy x
((7 == 5) || 10) || 15 // Kolejność operatorów
((false) || 10) || 15 // Ewaluujemy podwyrażenie
(false || true) || 15 // Konwersja z int na bool
true || 15 // Ewaluujemy podwyrażenie
true || true // Konwersja z int na bool
true // Ewaluujemy wyrażenie

Konkluzja

Podsumowaując, nauczyliśmy się:

To była długa podróż, ale umiejętności, które zebrałeś w tej lekcji są bardzo ważne dla przyszłej drogi. Przeczytaj kilka razy koncepcje przedstawione w tej lekcji, ponieważ podstawy wyrażeń logicznych i instrukcji warunkowych są bardzo ważną umiejętnością.