Rozważmy klasę SortedDir - kolejną klasę pochodną klasy ContactDir, implementowanej na poprzednim laboratorium. W klasie SortedDir każdy kontakt jest wstawiany w taki sposób, że lista kontaktów jest zawsze uporządkowana (np.alfabetycznie według nazwisk).
Zastosowanie klasy SortedDir pozwala przyspieszyć przeszukiwanie tablicy kontaktów (wyszukiwanie binarne,a nie liniowe jak w klasie ContactDir), choć z drugiej strony operacja wstawienia kontaktu jest w klasie SortedDir bardziej czasochłonna.
Klasa ContactDir posiada dwie metody związane z wyszukiwaniem: metodę publiczną Find, zwracającą wskaźnik do wyszukanego kontaktu oraz metodę prywatną Lookup, zwracającą indeks w tablicy Contacts wyszukanego kontaktu. Funkcja ContactDir::Lookup jest wykorzystywana przez metody publiczne Find, Insert i Delete klasy ContactDir.
Klasa SortedDir dziedziczy metody ContactDir, co oznacza, że metody Find, Insert i Delete klasy SortedDir będą używać metody ContactDir::Lookup, nawet jeśli w implementacji klasy SortedDir zdefiniujemy metodę SortedDir::Lookup
Oznacza to, że przedefiniowanie funkcji Lookup w implementacji SortedDir nie poprawi nam szybkości działania wyszukiwania, dopóki nie podejmiemy odpowiednich środków zaradczych. Generalnie mamy dwie możliwości: złą i dobrą. Zła metoda polega na zdefiniowaniu metod SortedDir::Find, SortedDir::Insert, SortedDir::Delete - to rozwiązanie jest zaprzeczeniem idei dziedziczenia.
Dobra metoda to zastosowanie funkcji wirtualnej. W definicji klasy ContactDir określamy metodę Lookup jako wirtualną:
class ContactDir
{
//...
protected:
virtual int Lookup(const char *name)
//...
};
W definicji klasy SortedDir również określamy metodę Lookup jako wirtualną:
class SortedDir
{
//...
protected:
virtual int Lookup(const char *name)
//...
};
Dzięki temu, że metoda Lookup jest wirtualna, przedefiniowanie tej w implementacji SortedDir sprawi, że wszystkie metody SortedDir dziedziczone z ContactDir (Find, Delete, Insert) będą używały metody Lookup związanej z obiektem, który te metody woła.
Klasa pochodna może mieć więcej, iż jedną klasę bazową. Rozważmy dla przykładu klasę OptionList, reprezentującą listę opcji, i klasę Window, reprezentującą okno - interfejs graficzny:
class OptionList
{
public:
OptionList(int n)
~OptionList(void)
//...
};
class Window
{
public:
Window(Rect &bounds);
~Window(void);
//...
};
Niech klasa Menu reprezentuje graficzny interfejs dla listy opcji - klasa Menu dziedziczy zatem zarówno po Window jak i po OptionList:
class Menu : public OptionList, public Window
{
public:
Menu(int n, Rect &bounds);
~Menu(void)
//...
};
Ponieważ klasy bazowe Menu mają konstruktory, przyjmujące argumenty, konstruktor Menu musi się do tych konstruktoróww odpowiedni sposób odwołać (member initialization list):
Menu::Menu (int n, Rect &bounds) : OptionList(n), Window(bounds)
{
//...
}
Proszę zaimplementować klasę SortedDir i odpowiednio zmienić implementację klasy CotactDir, aby w ich definicjach znalazła się wirtuala metoda Lookup. Proszę zademonstrować działanie metody wirtualnej Lookup dla klasy ContactDiri SortedDir.
Proszę zaimplementować klasy o opisanych poniżej cechach:
Klasa Image to klasa do manipulacji obrazami dwuwymiarowymi. Jej pola prywatne to bufor na dane (wskaźnik na typ char), wysokość i szerokość oraz typ (CHAR, SHORT, INT, LONG, FLOAT, DOUBLE). W buforze przechowywane są informacje o wartościach sygnału w poszczególnych pikselach obrazu. Pamięć na obraz jest rezerwowana w momencie tworzenia obiektu. Na obrazie możemy wykonywać operacje: pobranie z pliku, zapisanie do pliku, negatyw, utworzenie histogramu (i wiele innych, których nie implementujemy na laboratorium).
Klasa ListItem to klasa, której pola prywatne to wskaźnik na char, wskaźnik na element następny i poprzedni na.Klasa ma metody pozwalające pobierać i ustawiać wskaźniki.
Klasa List to kolekcja obiektów ListItem, zawierająca ponadto pole prywatne - aktualną długość listy oraz wskaźnik na pierwszy element listy. Metody- usuwanie na określonej pozycji, dodawanie na określonej pozycji, pobieranie aktualnego rozmiaru.
Klasa Image3DStack dziedziczy po List i po Image - pozwala na manipulacje obrazem trójwymiarowym. Konstruktor Image3DStack przyjmuje jako argument m.in. referencję do List i na tej podstawie rezerwuje bufor na dane trójwymiarowe.