1 Dziedziczenie. 1.1 Koncepcja dziedziczenia. Ćwiczenie 3



Podobne dokumenty
1 Definiowanie prostych klas

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Mechanizm dziedziczenia

TEMAT : KLASY DZIEDZICZENIE

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Mechanizm dziedziczenia

Wprowadzenie do programowanie obiektowego w języku C++

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Wykład 5: Klasy cz. 3

Dziedziczenie. Streszczenie Celem wykładu jest omówienie tematyki dziedziczenia klas. Czas wykładu 45 minut.

Programowanie strukturalne i obiektowe. Funkcje

C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie C++ - DZIEDZICZENIE.

Wykład 8: klasy cz. 4

Programowanie obiektowe

Języki i techniki programowania Ćwiczenia 3 Dziedziczenie

Programowanie obiektowe, wykład nr 6. Klasy i obiekty

Wprowadzenie do programowanie obiektowego w języku C++

Dziedziczenie. Zadanie 1

Wykład 4: Klasy i Metody

Rozdział 4 KLASY, OBIEKTY, METODY

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Aplikacje w środowisku Java

Zaawansowane programowanie w języku C++ Programowanie obiektowe

Informatyka I. Dziedziczenie. Nadpisanie metod. Klasy abstrakcyjne. Wskaźnik this. Metody i pola statyczne. dr inż. Andrzej Czerepicki

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

class Student Deklaracja klasy Osoba: Deklaracja klasy Student:

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

Informatyka II Laboratorium 3 : Programowania obiektowe C++ - dziedziczenie

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

2. Klasy cz. 2 - Konstruktor kopiujący. Pola tworzone statycznie i dynamicznie - Funkcje zaprzyjaźnione - Składowe statyczne

Szablony funkcji i szablony klas

Programowanie w C++ Wykład 13. Katarzyna Grzelak. 4 czerwca K.Grzelak (Wykład 13) Programowanie w C++ 1 / 26

Programowanie obiektowe

Programowanie obiektowe w języku C++

2.4 Dziedziczenie. 2.4 Dziedziczenie Przykłady programowania w C - kurs podstawowy

Dziedziczenie. Ogólna postać dziedziczenia klas:

Wprowadzenie w dziedziczenie. Klasa D dziedziczy klasę B: Klasa B klasa bazowa (base class), klasa D klasa pochodna (derived class).

Dziedziczenie jednobazowe, poliformizm

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Część XVII C++ Funkcje. Funkcja bezargumentowa Najprostszym przypadkiem funkcji jest jej wersja bezargumentowa. Spójrzmy na przykład.

Programowanie obiektowe

Polimorfizm. dr Jarosław Skaruz

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Projektowanie obiektowe. Roman Simiński Polimorfizm

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

> C++ dziedziczenie. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

10. Programowanie obiektowe w PHP5

WSNHiD, Programowanie 2 Lab. 2 Język Java struktura programu, dziedziczenie, abstrakcja, polimorfizm, interfejsy

Programowanie komputerowe. Zajęcia 7

Klasy abstrakcyjne i interfejsy

Programowanie obiektowe w języku

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Typy zmiennych proste i złożone. Programowanie komputerów. Tablica. Złożone typy zmiennych. Klasa. Struktura

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 4. Karol Tarnowski A-1 p.

Programowanie obiektowe

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

Dziedziczenie i interfejsy

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Funkcje przeciążone, konstruktory kopiujące, argumenty domyślne

dr inż. Jarosław Forenc

Dokumentacja do API Javy.

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Podstawy Programowania Obiektowego

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Programowanie II. Lista 3. Modyfikatory dostępu plik TKLientBanku.h

Dziedziczenie. Tomasz Borzyszkowski

1 Wskaźniki i zmienne dynamiczne, instrukcja przed zajęciami

Wprowadzenie do programowanie obiektowego w języku C++

Materiały do zajęć VII

Programowanie obiektowe

Polimorfizm, metody wirtualne i klasy abstrakcyjne

PHP 5 język obiektowy

Laboratorium 1 - Programowanie proceduralne i obiektowe

Programowanie obiektowe

Deklaracja i definicja metod, zwracanie wartości z metod, przekazywania parametrów do metod

Operator przypisania. Jest czym innym niż konstruktor kopiujący!

.NET Klasy, obiekty. ciąg dalszy

Wyjątki (exceptions)

Deklaracja struktury w C++

Programowanie Obiektowe i C++

Programowanie w języku C++

Instytut Mechaniki i Inżynierii Obliczeniowej Wydział Mechaniczny Technologiczny Politechnika Śląska

Zaawansowane programowanie w C++ (PCP)

C++ - [4-7] Polimorfizm

int suma; pralka czerwona; // definicja egzemplarza obiektu pralka * wskaŝ; // definicja wskaźnika pralka & ruda = czerwona; // definicja referencji

Jak napisać program obliczający pola powierzchni różnych figur płaskich?

Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu.

Wykład V. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

4. Funkcje. Przykłady

PARADYGMATY PROGRAMOWANIA Wykład 4

Widoczność zmiennych Czy wartości każdej zmiennej można zmieniać w dowolnym miejscu kodu? Czy można zadeklarować dwie zmienne o takich samych nazwach?

Podstawy programowania w języku C++ Zadania - dziedziczenie i polimorfizm

Klasa, metody, rozwijanie w linii

Języki Programowania. Prowadząca: dr inż. Hanna Zbroszczyk. tel: Konsultacje: piątek:

Funkcje wirtualne. Wskaźniki do klas pochodnych są podstawą dla funkcji wirtualnych i polimorfizmu dynamicznego.

Język C++ umożliwia przeciążanie operatora, tzn. zmianę jego znaczenia na potrzeby danej klasy. W tym celu definiujemy funkcję o nazwie:

Transkrypt:

Ćwiczenie 3 1 Dziedziczenie Ćwiczenie to poświęcone jest poznaniu podstawowych zagadnień związanych dziedziczeniem procesem budowania nowych klas, w oparciu o klasy istniejące. Obejmuje m.in. ćwiczenia pozwalające opanować definiowanie klas pochodnych, definiowanie konstruktorów tych klas, redefinicję metod oraz rozbudowę listy pól. Materiał teoretyczny, niezbędny dla zrozumienia prezentowanych przykładów, zawierają materiały wykładowe dostępne online, w postaci dokumentu pdf, pod adresem: http://www.us.edu.pl/~siminski. 1.1 Koncepcja dziedziczenia Koncepcja dziedziczenia (ang. inheritance) pozwala na budowanie nowych klas z wykorzystaniem klas już istniejących. Te nowe klasy, nazywane są klasami pochodnymi, zaś klasy stanowiące podstawę dziedziczenia, nazywamy klasami bazowymi. Dziedziczenie jest zatem procesem tworzenia klas potomnych (ang. derivation). Dziedziczenie pozwala urzeczywistnić pomysł powtórnego wykorzystania kodu. Koncepcja ta w oryginale nosi angielską nazwę code reusability. Dzięki temu podejściu nie trzeba tworzyć klas od nowa, o ile istnieją takie, które można rozszerzyć lub zaadaptować do stojących przed programistą zadań. Prześledźmy to na następującym przykładzie. Załóżmy, że naszym zadaniem jest napisanie programu obliczającego pole i objętość sześcianu (ang. cube). Sześcian jest oparty na kwadracie, o jego polu i objętości decyduje długość boku jednej ze ścian. A każda z nich jest kwadratem. Można zatem założyć, że sześcian to specyficzny kwadrat wyciągnięty w przestrzeni, obdarzony trzecim wymiarem. Ilustruje to Rysunek 1. W trakcie opracowania programów z Ćwiczenia 1-szego, należało opracować klasę Square (kwadrat). Klasa ta definiowała kwadrat, jako figurę geometryczną określoną długością boku pamiętaną w polu o nazwie side (bok). Klasa ta definiowała również funkcję składową area, obliczającą pole kwadratu. Nasuwa się pytanie czy można wykorzystać istniejący już kod klasy Square do utworzenia klasy reprezentującej sześcian? Niech ta klasa nazywa się Cube. Rzeczywiście, klasa Square może posłużyć jako klasa bazowa do opracowania klasy

2 Kwadrat Sześcian bok Cube. Niestety, funkcja area klasy Square oblicza pole kwadratu a nie sześcianu trzeba będzie coś z tym zrobić. Klasa Square nie posiada również funkcji obliczającej objętość (ang. volume). Trzeba ją będzie zdefiniować. Rysunek 1 Od kwadratu do sześcianu koncepcja dziedziczenia Zacznijmy jednak od klasy Square. Jej definicja jest następująca: class Square public : Square(); Square( double side ); void setside( double side ); double getside(); double area(); private: double side; ; bok A definicje funkcji składowych mają następującą postać: Square::Square() : side( 0 ) Square::Square( double side ) : side( side ) void Square::setSide( double side ) Square::side = side; double Square::getSide() return side; double Square::area()

return side * side; Koncepcję dziedziczenia ilustruje Rysunek 2. Po lewej diagram wg. zunifikowanej notacji obiektowej (język UML). Umieszczono na nim inne od konstruktorów składowe klasy Square. Składowe poprzedzone znakiem (+) to składowe publiczne, znakiem ( ) to składowe prywatne. Strzałka oznacza dziedziczenie, grot wskazuje klasę bazową. Prawa część rysunku symbolicznie ilustruje to, że obiekt klasy Cube będzie zawierał w sobie wszystko to, co obiekt klasy Square, oraz dodatkowe dwie funkcje składowe. Square +void setside( double side ) +double getside() +double area() -bok: double Cube +double volume() +double area() +double volume() +double area() Cube Square +void setside( double side ) +double getside() +double area() -bok: double Rysunek 2 Diagram UML dla dziedziczenia Spróbujmy zbudować klasę Cube z wykorzystaniem koncepcji dziedziczenia. Klasę pochodną rozpoczynamy od następującej definicji: class Cube : public Square ; Specyfikacja umieszczona po znaku dwukropka oznacza, że klasa Cube powstaje z klasy Square, dziedzicząc wszystkie jej składowe pola i funkcje składowe. Słowo kluczowe public oznacza dziedziczenie w trybie publicznym, niech to oznacza w tym momencie, że ustalona w klasie Square widoczność składowych będzie taka sama w klasie Cube. W tym momencie można już od biedy korzystać z klasy Cube oczywiście nie da się zrobić z obiektem tej klasy niczego więcej niż z obiektem klasy Square. Rozszerzmy klasę Cube o deklarację funkcji obliczania objętości volume(): class Cube : public Square public: double volume(); ; oraz jej definicję: double Cube::volume()

4 return side * side * side; Niestety, próba kompilacji tak zdefiniowanej funkcji się nie powiedzie. Pole side jest bowiem prywatną własnością obiektów klasy Square i nie jest dostępne w funkcjach klasy pochodnej. Należy skorzystać z akcesora funkcji getside(): double Cube::volume() return getside() * getside() * getside(); Gdyby przyjrzeć się jednak wzorowi na objętość, można stwierdzić, że jest to iloczyn pola powierzchni podstawy i wysokości. Pole powierzchni podstawy to nic innego jak pole kwadratu. A klasa Square posiada przecież funkcję służącą do obliczania tegoż pola. Zatem funkcję volume() można przepisać jeszcze raz, w następujący sposób: double Cube::volume() return area() * getside(); Nową funkcję obliczającą objętość sześcianu można wykorzystać następująco: Cube c; c.setside( 10 ); cout << "Objetosc szescianu o boku: " << c.getside(); cout << " wynosi: " << c.volume() << endl; Podsumowanie Podsumowując, możemy stwierdzić, że klasa Cube dziedziczy wszystkie właściwości klasy Square. Zatem posiada w sobie wszystkie pola, takie jak klasa Square, i wszystkie zdefiniowane w tej klasie funkcje składowe. Wykorzystując dziedziczenie, udało się rozszerzyć funkcjonalność klasy bazowej o jedną, nową funkcję volume(). Wszystko to stało się bez pisania dodatkowego kodu, dziedziczenie pozwoliło utworzyć nową, działająca klasę poprzez napisanie 8-miu nowych linii kodu! 1.2 Redefiniujemy funkcję area() Zauważmy, że funkcja area() obliczająca w klasie Square pole kwadratu została odziedziczona przez klasę Cube. Programista może zatem ją wykorzystać:

Cube c; c.setside( 10 ); cout << "Pole szescianu o boku: " << c.getside(); cout << " wynosi: " << c.area() << endl;; Niestety, wynik będzie niepoprawny! Nie powinno to być zaskoczeniem odziedziczona funkcja składowa area() liczy dokładnie pole kwadratu i w żaden cudowny sposób nie zacznie samodzielnie liczyć pola sześcianu! Aby temu zaradzić należy w klasie Cube zadeklarować własną, specyficzną dla tej klasy wersję funkcji area(). Wersja ta, w obrębie tej klasy, przesłaniać będzie funkcję area() odziedziczoną po klasie Square. Inaczej mówiąc, deklarując klasę Cube dokonujemy redefinicji funkcji składowej area(). double Cube::area() return 6 * ( getside() * getside() ); Spróbujmy napisać program testujący dotychczasowe wyniki naszej pracy: Cube c; c.setside( 10 ); cout << "Szescian o boku: " << c.getside() << endl; cout << " Objetosc: " << c.volume() << endl; cout << "Powierzchnia: " << c.area() << endl; Zobaczmy wyniki jego działania prezentuje to Rysunek 3: Rysunek 3 Objętość i powierzchnia coś tu nie gra.... Powierzchnia się zgadza. Objętość nie. Dlaczego? Przypomnijmy sobie, jak zdefiniowana została funkcja składowa obliczająca objętość: double Cube::volume() return area() * getside(); Pole razy bok, niby dobrze, ale przecież to chodziło o pole kwadratu stanowiącego podstawę sześcianu! A my dokonaliśmy redefinicji funkcji area(), i ona teraz oblicza pole powierzchni nie kwadratu a sześcianu a to jest sześciokrotnie większe popatrzmy, na umieszczoną wyżej, definicję funkcji składowej Cube::area().

Co z tym zrobić? Funkcji volume() działa źle. Wywołuje funkcję obliczania pola sześcianu a nie kwadratu, stąd błędna wartość. Jak temu zaradzić? Odpowiedź tkwi w poprzednim zdaniu. Przeczytajmy je jeszcze raz. I co? Ano to, że funkcja volume() będzie działać dobrze, jeżeli zamiast funkcji area() klasy Cube, wywoła funkcję area() klasy Square. Ale jak to zrobić? Zobaczmy, czym różnią się definicje obu tych funkcji: double Square::area() return side * side; oraz double Cube::area() return 6 * ( getside() * getside() ); Oczywiście różnią się ich ciała. Ale przyjrzyjmy się nagłówkom. Nazwy niby takie same, ale przed nazwami, no właśnie, przed nazwami są kwalifikatory nazw w postaci nazwy klasy i operatora zakresu (::). Takich nazw kwalifikowanych można używać również przy wywołaniach funkcji, zatem definicję funkcji składowej volume() można teraz przepisać w następujący sposób: double Cube::volume() return Square::area() * getside(); Cos dziwnego? W żadnym wypadku. Przecież objętość sześcianu to pole powierzchni podstawy, będącej kwadratem, przemnożone przez długość boku. I to właśnie napisaliśmy powyżej. Zobaczmy wyniki działania poprawionego programu przedstawia je Rysunek 4. Rysunek 4 Poprawiona funkcja volume() wyniki działania programu No, jest wyraźnie lepiej. Dokonajmy teraz kolejnych remanentów. Definicja funkcji area() klasy Cube wygląda nieco siermiężnie. Powierzchnia sześcianu to sześciokrotność pola powierzchni jednego boku będącego, jak wiemy, kwadratem. Można zatem przepisać tą funkcję następująco: double Cube::area() return 6 * Square::area();

W tej wersji funkcji volume() czai się jednak pułapka. Załóżmy, że programista piszący tą funkcję pomylił się i napisał ją następująco: double Cube::area() return 6 * area(); Cóż takiego napisał? Ano napisał, że powierzchnia sześcianu to sześciokrotność powierzchni sześcianu! Brak nazwy kwalifikowanej Square:: a właśnie na jej zapomnieniu polegał błąd programisty spowoduje, że funkcja area() będzie wywoływała samą siebie! Mamy tutaj swoistą, niezamierzoną rekurencję, bez warunku jej zakończenia. Jak się zachowa program w takiej wersji? Proponuję eksperyment uruchomcie program z tak zdefiniowaną funkcją area(), skompilowany Waszym ulubionym kompilatorem, w Waszym ulubionym środowisku systemowym. Proponuję jednak przed uruchomieniem na wszelki wypadek zapisać wszystkie otwarte dokumentu. Podsumowanie Redefiniowanie funkcji składowych w klasach pochodnych pozwala na modyfikowanie ich działania tak, by było ono zgodne z wymaganiami stawianymi nowej klasie. Często jednak przykryta funkcja odziedziczona po klasie bazowej jest użyteczna. Aby się nią posłużyć, wystarczy jej wywołanie poprzedzić nazwą kwalifikowaną, zawierającą operator zakresu (::) poprzedzony nazwą klasy. Stosowanie nazw kwalifikowanych jest dobrą praktyką. Świadczy o tym najlepiej analizowany wyżej przykład. Zapobiegliwe stosowanie takich nazw, nawet, jeżeli pozornie nie wydaje się to konieczne, pozwala w przyszłości uniknąć wielu, dokuczliwych i trudnych w zlokalizowaniu błędów. 1.3 Konstruktory klasy pochodnej Klasa pochodna dziedziczy wszystkie składowe każdej klasy podstawowej, z wyjątkiem konstruktorów, destruktorów i operatorów przypisania. Warto sobie to zdanie zapamiętać, choć przynajmniej teoretycznie nie znamy jeszcze destruktorów i operatorów przypisania. Dla znamy już konstruktory. Konstruktory nie są dziedziczone. Przykładowo, nie powiedzie się próba skompilowania przedstawionego niżej kodu: Cube c( 10 ); cout << "Szescian o boku: " << c.getside() << endl; cout << " Objetosc: " << c.volume() << endl; cout << " Powierzchnia: " << c.area() << endl; W klasie Square zdefiniowano konstruktor ogólny:

Square::Square( double side ) : side( side ) Nie zostanie on jednak aktywowany automatycznie dla obiektu klasy Cube. W klasie pochodnej programista powinien zdefiniować konstruktory na nowo. Istnieje pewne rozluźnienie tej zasady, dotyczące konstruktorów domyślnych (bezparametrowych). Rozluźnienie to jest jednak mocno dyskusyjne, sam twórca języka Brajne Stroustrup namawia do definiowania również konstruktorów domyślnych klas pochodnych. Zapamiętajmy zatem: przy tworzeniu klasy pochodnej, programista zdefiniować powinien wszystkie niezbędne dla niej konstruktory. Aktywowanie konstruktora klasy bazowej Przy budowaniu klas pochodnych kierujemy się następującą zasadą: klasie pochodnej definiujemy metody do obsługi nowych pól, obsługę pól odziedziczonych realizujemy z wykorzystaniem metod odziedziczonych. Mimo, że konstruktory klasy pochodnej nie są jawnie dziedziczone, programista ma do nich dostęp. Może zatem aktywować je, i przy ich użyciu inicjować odziedziczone pola klasy bazowej. Definicja domyślnego konstruktora klasy Cube, inicjującego pole side z wykorzystaniem konstruktora klasy Square ma następującą postać: Cube::Cube() : Square() Na liście inicjalizacyjnej konstruktora klasy Cube umieszczono aktywowanie konstruktora domyślnego klasy Square. Co on robi? Ano przypisuje polu side domyślną wartość równą zero zobacz definicja konstruktora domyślnego klasy Square. Dlaczego aktywowanie konstruktora klasy bazowej odbywa się poprze umieszczenie go na liście inicjalizacyjnej a nie poprze jego jawne wywołanie w ciele konstruktora klasy Cube? W języku C++ zwykle nie wywołuje się jawnie konstruktorów, stąd mówimy raczej o aktywowaniu konstruktora na liście inicjalizacyjnej a nie jego wywołaniu. Lista inicjalizacyjna jest legalnym miejscem aktywowania konstruktora klasy bazowej. Definicja konstruktora ogólnego klasy Cube może być następująca: Cube::Cube( double side ) : Square( side ) Dlaczego w konstruktorach klasy Cube posługujemy się konstruktorami klasy bazowej a nie inicjujemy pola side własnoręcznie, np. w następujący sposób:

Cube::Cube() setside( 0 ); Cube::Cube( double side ) setside( side ); Owszem, można tak ale jakież to nieeleganckie! Oprócz tego, że nieeleganckie to rozrzutne i niezgodne z ideą programowania obiektowego. Przypomnijmy skoro konstruktor domyślny klasy Square jest po to, by zainicjować obiekt wartością domyślną pole side, to użyjmy go do zainicjowania tej właśnie części obiektu klasy Cube, która została odziedziczona z klasy Square. 1.4 Zadanie do wykonania W ramach ćwiczeń należy napisać obiektową wersję programu, pozwalającego na obliczanie pola powierzchni i objętości brył takich jak: sześcian, prostopadłościan, kula, graniastosłup o podstawie trójkąta. Każda z brył ma być opisana w postaci klasy, analogicznie do tego w jaki sposób zdefiniowano klasę Cube. I tak, kula dziedziczy właściwości po klasie opisu koła, prostopadłościan po prostokącie, ostrosłupy odpowiednio po trójkącie i trapezie. Każda z brył ma mieć zdefiniowaną funkcję obliczania objętości oraz zdefiniowaną ponownie funkcję obliczania pola powierzchni. W przypadku prostopadłościanu i graniastosłupa w klasie opisu danej bryły pojawić się musi nowe pole. W przypadku prostopadłościanu to długość krawędzi pionowej a w przypadku graniastosłupa to wysokość. Należy niezbędne pola zdefiniować w klasie pochodnej. Wszystkie niezbędne informacje na temat definiowania i inicjalizowania pól w klasie pochodnej zawierają materiały wykładowe, str. 28-31. Program ma działać analogicznie do programu obliczania pól figur płaskich z ćwiczenia 1. Ma być sterowany prostym menu tekstowy, pozwalającym na wybranie konkretnej bryły. Po jej wybraniu program mam wczytać parametry niezbędne do obliczenia pola powierzchni i objętości, co ma się odbyć obiektowo, w sposób analogiczny do opisanej klasy Cube.

Koncepcję utworzenia klasy opisu prostopadłościanu, w oparciu o klasę opisującą prostokąt ilustruje Rysunek 5. Klasa opisu prostopadłościanu posiadać będzie dodatkowe pole, przechowujące trzeci wymiar bryły. b b c a a Prostokąt Prostopadłościan Rysunek 5 Od prostokąta do prostopadłościanu 1.5 Co po tym ćwiczeniu należy umieć? Zakładam, że po tym ćwiczeniu każdy potrafi odpowiedzieć na pytanie i zastosować te wiadomości w praktyce: 1. Co to jest dziedziczenie? 2. Co to jest klasa bazowa a co klasa pochodna? 3. W jaki sposób dokonać rozszerzenia klasy pochodnej nowe pola i funkcje składowe? 4. W jaki sposób dokonuje się redefinicji funkcji składowej w klasie pochodnej i w jaki sposób odwołuje się do przesłoniętej funkcji składowej? 5. W jaki sposób definiuje się konstruktory klasy pochodnej, jak wygląda aktywowanie konstruktorów klas bazowych?