Laboratorium 2 Funkcje wirtualne Zadanie 1. Zapoznaj się z programem z pliku lab2-p1.cpp. Czy program działa prawidłowo? Dlaczego funkcja rachunek() jest zdefiniowana jako virtual? Co się stanie jeśli usuniemy ten modyfikator? (uruchom program i wyjaśnij, dlaczego tak się dzieje.) Zadanie 2. Uzupełnij podany program (jest on w pliku zad2.cpp). Klasa bazowa Zwierze opisuje zwierzę. Jej klasami pochodnymi są Ssak i Ryba. Klasa Ssak ma dwie klasy pochodne: Pies i Kon. #include <iostream> using namespace std; enum KOLOR Czerwony, Zielony, Niebieski, Szary, Bialy, Czarny, Brazowy ; class Zwierze Zwierze(int); virtual ~Zwierze() cout << "Zwierze usuwam...\n"; virtual int PodajWiek() const return jegowiek; virtual void UstawWiek(int wiek) jegowiek = wiek; virtual void Spij() const = 0; virtual void Jedz() const = 0; virtual void Rozmnazaj() const = 0; virtual void Idz() const = 0; virtual void DajGlos() const = 0; int jegowiek; ; class Ssak : public Zwierze // wstaw potrzebne funkcje... virtual void Rozmnazaj () const cout << "Rozmnazanie ssaka...\n"; ; class Ryba : public Zwierze // wstaw potrzebne funkcje... virtual void Rozmnazaj () const cout << "ryba sklada jaja...\n"; ; 1
class Kon : public Ssak protected: KOLOR jegokolor; // wstaw potrzebne funkcje ; class Pies : public Ssak protected: KOLOR jegokolor; // wstaw potrzebne składowe ; Zwierze *pzwierze=0; int wybor; bool koniec =false; while (1) cout << "(1)Pies (2)Kon (3)Ryba (0)Koniec: "; cin >> choice; switch (choice) case 1: pzwierze = new Pies(5,Brazowy); case 2: pzwierze = new Kon(4,Czarny); case 3: pzwierze = new Ryba (5); default: Koniec = true; if (koniec) pzwierze->dajglos(); pzwierze->jedz(); pzwierze->rozmnazaj(); pzwierze->idz(); pzwierze->spij(); delete pzwierze; cout << endl; return 0; Dziedziczenie wielobazowe Zadanie 3. Zbuduj klasę Osoba i pochodne po niej klasy Wykladowca i Student. Następnie utwórz klasę StudentWykladowca, dziedziczącą po klasach Wykładowca i Student. Klasa Osoba zawiera jedną składową przechowującą nazwisko. Klasa Wykladowca przechowuje informacje o wykładanym przedmiocie, klasa Student o przedmiocie, do którego przypisany jest student. Klasa StudentWykladowca zawiera informację o przedmiocie do którego przypisany jest student i do przedmiotu, który student jednocześnie wykłada. 2
Przykładowy program testujący utworzone klasy: // utworzobiekty Wykladowca wykladowca("nowak","podstawy programowania"); Student student("adamski", "Podstawy programowania"); StudentWykladowca stud_wykl("bury", "Podstawy programowania", "Wprowadzenie do sieci"); // zajmuja się swoimi obowiązkami wykladowca.info(); // przedstawia się wykladowca.naucza(); // wykonuje prace student.info(); student.studiuje(); stud_wykl.info(); stud_wykl.naucza(); stud_wykl.studiuje(); Zadania domowe Zadanie 4. Klasa Wektor implementuje dynamicznie alokowaną tablicę przechowującą liczby całkowite: class Wektor protected: int rozmiar; int *buf; Wektor(int n) rozmiar =n; buf = new int[n]; ~Wektor() delete [] buf; int dl() return rozmiar; ; Opracować klasę pochodną Stos, której zadaniem jest wstawianie i usuwanie elementów ze stosu. Co będzie składową tej klasy? Klasa powinna posiadać konstruktor, metodę Push i Pop oraz metodę zwracającą liczbę elementów przechowywanych na stosie. Zadanie 5 Prata, Szkoła Programowania C++, wyd.v, zadanie 1, str. 764 Rozpocznij od poniższej deklaracji klasy: // Klasa bazowa class Cd // Reprezentuje płyte CD 3
char performers[50]; char label[20]; int selections; // Liczba utworów double playtime; // Długość płyty w minutach Cd(char * s1, char * s2, int n, double x); Cd(const Cd & d); Cd(); ~Cd(); void Report() const; // Wyświetla informacje o wszystkich danych płyty CD Cd & operator=(const Cd & d); ; Utwórz klasę pochodną Classic i dodaj do niej składową typu char, która przechowuje ciąg znaków określający główny utwór na tej płycie. Odpowiednio zmodyfikuj deklarację klasy bazowej, jeśli potrzebne są w niej funkcje wirtualne. Jeśli któraś z zadeklarowanych metod nie jest potrzebna, usuń ją z definicji. Przetestuj klasy za pomocą poniższego programu: #include <iostream> using namespace std; #include classic.h // który zawiera #include cd.h void Bravo(const Cd & disk); Cd c1( Beatles, Capitol, 14, 35.5); Classic c2 = Classic( Sonata fortepianowa B-dur, Fantazja C-moll, Alfred Brendel, Philips, 2, 57.17); Cd *pcd = &c1; cout << Bezpośrednie użycie obiektu:\n ; c1.report(); // Używa metody klasy Cd c2.report(); // Używa metody klasy Classic cout << Użycie wskaźnika na typ Cd:\n ; pcd->report(); // Używa metody klasy Cd dla obiektu tej klasy pcd = &c2; pcd->report(); // Używa metody klasy Classic dla obiektu tej klasy cout << Wywoływanie funkcji z argumentem w postaci referencji do typu Cd:\n ; Bravo(c1); Bravo(c2); cout << Test przypisania: ; Classic copy; copy = c2; copy.report() return 0; void Bravo(const Cd & disk) disk.report(); 4
Zadanie 6 Prata, Szkoła Programowania C++, wyd.v, zadanie 2, str. 765 Wykonaj Zadanie 5., używając tym razem do przechowywania ciągów znaków dynamicznego przydziału pamięci zamiast tablic stałej wielkości Zadanie 7 Prata, Szkoła Programowania C++, wyd.v, zadanie 4, str. 765 Dobroczynny Zakon Programistów przechowuje kolekcję win. Aby ją opisać, Mistrz Win Zakonu zaprojektował klasę Port: #include <iostream> using namespace std; class Port char * brand; char style[20]; // Na przykład lekko brązowe, rubinowe, z najlepszego rocznika int bottles; Port(const char * br = Brak, const char * st = Brak, int b = 0); Port(const Port & p); // Konstruktor kopiujący virtual ~Port() delete [] brand; Port & operator=(const Port & p); Port & operator+=(int b); // Dodaje b do bottles Port & operator-=(int b); // Odejmuje b od bottles, jeśli operacja ta jest //możliwa int BottleCount() const return bottles; virtual void Show() const; friend ostream & operator<<(ostream & os, const Port & p); ; Metoda Show () wyświetla dane w formacie: Marka: Galio Rodzaj: lekkobrązowy Butelek: 20 Funkcja operator<< () wyświetla informacje w poniższym formacie bez znaku nowej linii na końcu: Galio, lekkobrązowe, 20 Mistrz Win napisał definicję metod klasy Port, a następnie zaczął pracę nad klasą pochodną VintagePort. Niestety, wkrótce został zwolniony ze swej funkcji, ponieważ omyłkowo pożyczył butelkę Cockbum rocznik 45 osobie przygotowującej eksperymentalny sos barbecue. Poniżej znajduje się kod, który udało się napisać Mistrzowi: class VintagePort : public Port // Styl zawsze "najlepszy rocznik" char * nickname; // Na przykład "Szlachetny", "Aksamitny" Int year; // Rok winobrania VintagePort(); VintagePort(const char * br, int b, const char * nn, int y); VintagePort(const VintagePort & vp); ~VintagePort() delete [] nickname; VintagePort & operator=(const VintagePort & vp); 5
; void Show() const; friend ostream & operator<<(ostream & os, const VintagePort & vp); Twoim zadaniem jest ukończenie klasy VintagePort. a) Po pierwsze, musisz odtworzyć definicje metod klasy Port, ponieważ poprzedni Mistrz Win przed zwolnieniem złożył je w ofierze. b) Po drugie, musisz wyjaśnić, dlaczego niektóre metody są powtórnie zdefiniowane, a inne nie. c) Po trzecie, musisz wytłumaczyć, dlaczego funkcje operator= () oraz operator<< () nie są wirtualne.. d) Po czwarte, musisz zdefiniować metody klasy VintagePort. Zadanie 8 Prata, Szkoła Programowania C++, wyd.v, zadanie 4, str. 858 Klasa Person (osoba) przechowuje imię i nazwisko osoby. Oprócz konstruktorów klasa posiada metodę Show(), która wyświetla imię i nazwisko. Klasa Gunslinger (rewolwerowiec) dziedziczy po klasie Person. Posiada ona dodatkowo metodę Draw(), która zwraca liczbę zmiennoprzecinkową reprezentującą czas wyciągania rewolweru przez rewolwerowca. W klasie znajduje się też składowa w postaci liczby całkowitej, które reprezentuje liczbę nacięć na rewolwerze. Metoda Show() w tej klasie wyświetla wszystkie te informacje. Klasa PokerPlayer (pokerzysta) dziedziczy wirtualnie po klasie Person. Posiada metodę Draw(), która zwraca liczbę losową między 1 a 52 reprezentującą kartę. Możesz też zdefiniować klasę Card z kolorem i numerem, a następnie używać typu Card jako wartości zwracanej przez metodę Draw(). Klasa PokerPlayer używa funkcji Show() z klasy Person. Klasa BadDude dziedziczy publicznie po klasach Gunslinger oraz PokerPlayer. Znajduje się w niej metoda Gdraw(), która zwraca czas wyciągania rewolweru i metodę Cdraw(), która zwraca następną wyciągniętą kartę. Klasa posiada również odpowiednią funkcję Show(). Zdefiniuj wszystkie te klasy i metody, jak również inne metody, które okażą się niezbędne. Napisz program testujący, podobny (ale nie identyczny) do programu przytoczonego poniżej: Przykład plik workmi.cpp // workmi.cpp dziedziczenie wielokrotne #include <iostream> #include <cstring> #include workermi.h const int SIZE = 5; using std::cin; using std::cout; using std::endl; using std::strchr; Worker * lolas[size]; int ct; for (ct = 0; ct < SIZE; ct++) char choice; cout << Enter the employee category:\n << w: waiter s: singer << t: singing waiter q: quit\n ; cin >> choice; while (strchr( wstq, choice) == NULL) cout << Please enter a w, s, t, or q: ; 6
cin >> choice; if (choice == q ) switch(choice) case w : lolas[ct] = new Waiter; case s : lolas[ct] = new Singer; case t : lolas[ct] = new SingingWaiter; cin.get(); lolas[ct]->set(); cout << \nhere is your staff:\n ; int i; for (i = 0; i < ct; i++) cout << endl; lolas[i]->show(); for (i = 0; i < ct; i++) delete lolas[i]; cout << Bye.\n ; return 0; 7