Szablony klas na przykładzie własnej kolejki LIFO (stosu)

Stronę tą wyświetlono już: 280 razy

Wstęp

Zanim przejdę do konkretnego przykładu, który nie jakoby przyobiecałem muszę opisać pokrótce sposób tworzenia szablonów klas. Wcześniej już omawiane były szablony funkcji na stronie Programowanie → Podstawy C++ → Szablony funkcji a więc słowa kluczowe template oraz typename powinny być Ci już znane. Oto prosty przykład deklaracji szablonu klasy:

Listing 1
  1. #include <iostream>
  2. template <typename typ1, class typ2> class A // tutaj zadeklarowałem użycie dwóch typów danych
  3. {
  4. private:
  5. typ1 t1; // tutaj będzie deklarowana zmienna typu typ1
  6. public:
  7. typ2 t2; // a tu obiekt klasy typu typ2
  8. // To jest konstruktor szablonu klasy A
  9. A(typ1 t1, typ2 &t2):t1(t1),
  10. t2(t2)
  11. {};
  12. inline typ1 GetT1(){return t1;}; // to jest metoda zwracająca wartość pola t1
  13. void SetT1(typ1 t1){this->t1 = t1;}; // to jest metoda ustawiająca wartość pola t1
  14. };
  15. class B // przykładowa klasa testowa
  16. {
  17. private:
  18. int value;
  19. int value2;
  20. public:
  21. B():value(0),value2(0){}; // prosty domyślny konstruktor
  22. };
  23. int main(){
  24. B b;
  25. A<int, B>(10,b); // tworzenie konkretnego obiektu według szablonu klasy A
  26. cout<<"Wcisnij enter, aby zamknac program...";
  27. cin.get();
  28. return 0;
  29. }

Tworzenie własnej klasy kolejki LIFO

LIFO (skrót od last in first out - ostatni wchodzi pierwszy wychodzi) to sposób przechowywania danych w taki sposób, że ostatni element danych zawiera wskaźnik do wcześniej dodanych elementów. Efektem tego, aby zdjąć i-ty element stosu trzeba najpierw zdjąć wszystkie jego nadrzędne elementy. Sytuację tą często porównuje się do stosu książek, aby spod takiego stosu wyjąć jakąś książkę, trzeba najpierw zdjąć te leżące nad.

Oto przykład szablonu klasy stack oraz dodatkowo definicji klasy typy point2d:

Listing 2
  1. #include <iostream>
  2. using namespace std;
  3. template <typename type> class stack{
  4. private:
  5. type value; // element zawarty w stosie
  6. stack* st; // wskaźnik do wcześniej dodanych elementów stosu
  7. public:
  8. stack(type value):st(NULL),value(value){}; // konstruktor tworzący pierwszy element stosu
  9. stack(type value,stack* st):st(st),value(value){}; // konstruktor tworzący kolejny element stosu
  10. void Add(stack** pts, type value){stack* s = new stack(value,this);*pts = s;}; // dodawanie elementu stosu
  11. void RemoveStack(stack** pts){stack* st2 = st; st = NULL, delete this; *pts = st2;}; // usuwanie elementu stosu
  12. ~stack(){if(st){delete st; st=NULL;}cout<<"Pointer stack is deleted"<<endl;}; // zwalnianie pamięci stosu
  13. void WriteAllStack(){value.Write();if(st){st->WriteAllStack();}}; // wypisywanie elementów stosu
  14. int Size(){int s = 1; stack* st2 = st;while(st2){s++; st2 = st2->st;}return s;}; // pobieranie liczby elementów stosu
  15. };
  16. class point2d{
  17. protected:
  18. double x; // współrzędna x
  19. double y; // współrzędna y
  20. public:
  21. point2d():x(0),y(0){}; // Konstruktor ustawiajacy domyślne współrzędne
  22. point2d(point2d &p):x(p.x),y(p.y){}; // Konstruktor kopiujący
  23. point2d(double x,double y):x(x),y(y){}; // Konstruktor ustawiający podanymi liczbami
  24. void operator = (point2d &p){x = p.x; y = p.y;}; // Operator podstawiający
  25. void operator *=(double k){x *= k; y *= k;};
  26. void Write(){std::cout<<"x="<<x<<"; y="<<y<<"n";}; // Wypisywanie współrzędnych punktu na ekranie
  27. inline double GetX() const {return x;}; // Pobieranie wartości współrzędnej x
  28. inline double GetY() const {return y;}; // Pobieranie wartości współrzędnej y
  29. void SetX(double x){this->x=x;}; // Ustawianie wartości współrzędnej x
  30. void SetY(double y){this->y=y;}; // Ustawianie wartości współrzędnej y
  31. ~point2d(){}; // Destruktor
  32. };

W powyższym kodzie znalazła się taka oto metoda szablonu klasy A:

Listing 3
  1. void WriteAllStack(){value.Write();if(st){st->WriteAllStack();}}; // wypisywanie elementów stosu

Warto się jej przyjrzeć, ponieważ w ta metoda wywołuje metodę wewnętrzną obiektu pola klasy value.Write(), a to z kolei oznacza, że do stosu mogą być dodawane jedynie takie obiekty klas, które w swej definicji mają zadeklarowaną funkcję Write().

Poniżej zamieszczam przykładowy kod pokazujący operacje na stosie:

Listing 4
  1. int main(){
  2. // Dodawanie elementów stosu
  3. point2d p(0,0);
  4. sPoints = new stack<point2d>(p); // tworzenie pierwszego elementu stosu zawierającego obiekt klasy typu point2d
  5. for(int i = 0; i < 10; i++){
  6. point2d p(i,i);
  7. sPoints->Add(&sPoints, p); // dodawanie nowego elementu stosu
  8. }
  9. cout<<endl<<"Wypisywanie elementow stosu:"<<endl<<endl;
  10. sPoints->WriteAllStack(); // wypisuję elementy stosu
  11. cout<<endl<<"Usuwanie elementu stosu:"<<endl<<endl;
  12. sPoints->RemoveStack(&sPoints); // usuwa ostani element stosu
  13. cout<<endl<<"Wypisywanie elementow stosu:"<<endl<<endl;
  14. sPoints->WriteAllStack(); // wypisuję elementy stosu
  15. cout<<endl<<"Usuwanie elementu stosu:"<<endl<<endl;
  16. sPoints->RemoveStack(&sPoints);
  17. cout<<endl<<"Wypisywanie elementow stosu:"<<endl<<endl;
  18. sPoints->WriteAllStack();
  19. cout<<endl<<"Liczba elementow stosu: "<<sPoints->Size()<<endl; // tutaj metoda Size() określa ile elementów znajduje się w stosie
  20. cout<<endl<<"Zwalnianie pamieci stosu:"<<endl<<endl;
  21. if(sPoints){ // jeżeli sPoinr ma przypisaną pamięc to
  22. delete sPoints; // zwolnij pamięć
  23. sPoints = NULL; // i przypisz zero
  24. }
  25. cout<<endl;
  26. cout<<"Wcisnij enter, aby zamknac program...";
  27. cin.get();
  28. return 0;
  29. }

Komentarze