Wykład 5
Dziedziczenie jednobazowe
1. Podstawowe definicje
2. Konstruktory w klasach dziedziczących
3. Dziedziczenie metod i operatorów bez przedefiniowania 4. Dziedziczenie metod i operatorów z przedefiniowaniem
5.
Dziedziczenie klas z polami dynamicznymi - definicje konstruktorów zwykłych i kopiowania, destruktorów, przeciążenie operatorów przypisania=, dziedziczenie metod bez/z przedefiniowaniem
1.Podstawowe definicje
Dziedziczenie to jeden z podstawowych paradygmatów programowania obiektowego (wykład 1).
Pozwala na zdefiniowanie klasy pochodnej B na podstawie istniejącej klasy A, zwanej klasą bazową:
class B : public A // lub private A { //definicja nowych metod i pól
// przedefiniowanie istniejących metod
gdzie public - dziedziczenie publiczne; }; private - dziedziczenie prywatne
6. 2. Dostęp do składowych klasy bazowej A
·
w przypadku dziedziczenia typu public: dostęp klasy-następcy B do wszystkich składowych publicznych klasy bazowej A
·
w przypadku dziedziczenia typu private: składowe publiczne z klasy bazowej A stają się składowymi prywatnymi w klasie pochodnej (np. do całkowitej zmiany interfejsu).
·
w obu przypadkach dziedziczenia składowe prywatne nie są udostępniane klasie-następcy B
·
w celu ochrony składowych klasy bazowej A (hermetyzacja) można zastąpić specyfikator dostępu private specyfikatorem protected: takie składowe są publiczne dla klasy-następcy B, natomiast są prywatne dla jej dla użytkownika
·
jeśli metoda klasy A została przedefiniowana w klasie-następcy B, to w ciele metod klasy B można wywołać pierwotną metodę za pomocą operatora ::
np. A::metoda_p();
·
metody dziedziczone z przedefiniowaniem na rzecz obiektu klasy B są wywoływane za pomocą operatora ::
// metoda_p() jest dziedziczona z przedefiniowaniem od klasy A np. B b; b.A::metoda_p();
·
metody dziedziczone bez przedefiniowania można wywołać bezpośrednio w ciele metod klasy- następcy B
np. metoda();
·
metody dziedziczone na rzecz obiektu klasy B są wywoływane tak samo jak metody zdefiniowane w klasie B
np. B b; b.metoda (); //metoda() jest dziedziczona od klasy A 1.3. Wywołanie konstruktorów i destruktorów
Tworzeniu obiektu następcy B towarzyszy wywołanie niejawne jego
konstruktora i automatyczne wywołanie konstruktora z klasy A. W przypadku
braku listy argumentów w konstruktorze B, wywoływany jest konstruktor bezargumentowy klasy A (jawny lub domniemany). W przypadku zastosowania listy argumentów w klasie pochodnej B, można wybrać rodzaj konstruktora z klasy bazowej A do inicjowania pól dziedziczonych w B:
B(typ_1 a_1, ...typ_n a_n) : A(a_1, a_2);
Podczas usuwania obiektu wywoływany jest najpierw destruktor (jawny lub domniemany) klasy B, a potem destruktor klasy bazowej A (jawny lub domniemany).
1.4. Wywołanie konstruktora kopiującego
·
w przypadku, gdy w klasie B nie ma jawnego konstruktora kopiującego:
wywoływany jest konstruktor kopiujący domniemany, który wywołuje konstruktor kopiujący z A (jawny lub domniemany, inicjujący pola w B odziedziczone od A) i inicjuje pozostałe pola w B
·
w przypadku, gdy w klasie B jest jawny konstruktor kopiujący z listą argumentów: wywołuje on dowolny konstruktor klasy bazowej A, wymieniony w liście (kopiujący lub zwykły) np.:
·
konstruktor kopiujący z klasy A:
B(B&b) : A(b)
(wywołanie konstruktora kopiującego z A, do którego zostanie przekazana część obiektu klasy B odziedziczona od klasy A);
·
konstruktor zwykły z klasy A:
B(B&b) : A(b.skladowa_1(), b.skladowa_2())
(wywołanie zwykłego konstruktora z klasy bazowej A, do którego przekazuje się dane odziedziczone przez obiekt klasy B od klasy A)
·
w przypadku, gdy w klasie B jest jawny konstruktor kopiujący, lecz nie
zastosowano listy argumentów: wywołuje on konstruktor bezargumentowy
klasy A (jawny lub domniemany)
1.5. Własności
·
nie można zmienić pól zdefiniowanych w klasie bazowej
· można przedefiniować metody w klasie pochodnej
·
metody dziedziczone działają na obiekcie klasy pochodnej B tak, jak gdyby był obiektem klasy bazowej A,
· dziedziczeniu nie podlegają: konstruktory, destruktory, operator = oraz zaprzyjaźnienia
· istnieją standardowe konwersje typu z klasy pochodnej do klasy bazowej dla obiektów, wskaźników i referencji, dostępne poza zakresem klasy
pochodnej w przypadku publicznej klasy bazowej:
klasa_bazowa ® klasa_pochodna klasa_bazowa * ® klasa_pochodna * klasa_bazowa & ® klasa_pochodna &
W wyrażeniu obiekt_klasy_bazowej = obiekt_klasy_pochodnej kopiowane są tylko pola wspólne w obu klasach w wyniku dziedziczenia
np. punkt p1(1, 2), p2, *p3 kolo k1(2, 3, 4), k2, *k3;
p1 = p2 k2 = k1
k3 = &k2
kolo & k4 = k2
// kopiowane są tylko składowe x i y od obiektu klasy kolo p2 = k1
//zmienna wskaźnikowa p3 jest adresem części klasy punkt w obiekcie k1 klasy //kolo
p3 = &k1 p3 = k3
//zmienna referencyjna p4 jest częścią klasy punkt w obiekcie k2 klasy kolo punkt & p4 = k2
Odwrotne przypisania są błędne, lecz możliwe jest rzutowanie wskaźników:
np. k3 = (kolo*) p3
lub zastosowanie konwersji konstruktorowej kolo::kolo(punkt), tworzącej z obiektu p1 typu punkt obiekt klasy kolo
np. k1 = p1
2. Konstruktory w klasach dziedziczących Przykład 1
Zrealizować klasę kolo do obsługi kół na płaszczyźnie na podstawie klasy punkt, uzupełniając dane o promień. Należy wykonać konstruktory: zwykły i kopiujący, bez stosowania listy argumentów, w obu klasach punkt i kolo.
...
#include "kolo5_1.h"
#include "punkt5_1.h"
...
void wyswietl(kolo&);
void wyswietl(punkt&);
void wyswietl(float);
void wyswietl(int, int);
void main() { clrscr();
{ wyswietl(kolo::liczba_kol(), kolo::info());
wyswietl(punkt::liczba_punktow(), punkt::info());
/*Wywołanie konstruktorów kola i punktu, lecz z powodu braku listy argumentów, wywołany jest domyślnie bezparametrowy konstruktor punktu, stąd w konstruktorze kola występuje przypisanie (2,2) oraz (1,5) do danych x, y dziedziczonych od punktu*/
kolo k1(2, 2, 3), k2(1, 5, 6);
wyswietl(k1); wyswietl(k2);
wyswietl(kolo::liczba_kol(), kolo::info());
wyswietl(punkt::liczba_punktow(), punkt::info());
/*Wywołanie dziedziczonej metody odleglosc z klasy punkt. Obiekt k2 przy przekazywaniu przez listę parametrów metody jest ograniczony do klasy punkt.*/
wyswietl(k1.odleglosc(k2));
/*Kopiowanie obiektu k1 typu kolo za pomocą konstruktora kopiującego kola i zwykłego konstruktora punktu bezparametrowego z powodu braku listy w konstruktorze kola i utworzenie nowego obiektu k3 typu kolo */
kolo k3 = k1;
wyswietl(k3);
}
wyswietl(kolo::liczba_kol(), kolo::info());
wyswietl(punkt::liczba_punktow(), punkt::info());
}
void wyswietl(kolo& k) {punkt pom;
/*Mozna przypisywać następcę do poprzednika lub obiekty z tych samych klas. Ograniczenie obiektu k typu kolo do obiektu pom typu punkt zapobiega rekurencyjnemu wywołaniu funkcji przeciążonej funkcji wyswietl dla kola*/
pom = k;
wyswietl(pom);
cout <<"Promien: " << k.p_promien() << '\n'; getch();}...
#include "punkt5_1.h" // plik nagłówkowy kolo5_1.h class kolo:public punkt
{ static int ile_kol; //kolo posiada wszystkie pola klasy punkt oraz własne:
float promien; //ile_kol oraz promien public: kolo (float = 0.0, float = 0.0, float = 0.0);
kolo(kolo&);
~kolo();
float pole() const;
static int liczba_kol(); //dziedziczy wszystkie metody oprócz static int info(); //konstruktorów, destruktora
float& p_promien();}; //metoda do czytania i zapisu składowej promien
class punkt //plik nagłówkowy punkt5_1.h
{ static int ile_punktow;
float x,y;
public: punkt (float = 0.0, float = 0.0);
punkt(punkt&);
~punkt();
void przesun (float, float);
float odleglosc(const punkt&) const;
static int liczba_punktow();
static int info();
float& odcieta(); //metoda do czytania i zapisu składowej x float& rzedna();}; //metoda do czytania i zapisu składowej y
#include "kolo5_1.h" //plik za definicjami metod kolo5_1.cpp
#include "punkt5_1.h"
kolo::kolo(float xx, float yy, float rr)
{ odcieta() = xx; //wywołanie metod w trybie do zapisu składowych
rzedna() = yy;
promien = rr;
/*po nadaniu atrybutu protected polom w klasie punkt można bezpośrednio odwołać się do dziedziczonych pól: x = xx; y = yy;*/
cout<<"Konstruktor zwykly kola\n"; ile_kol++; } kolo::kolo(kolo& p)
{ //wywołanie metod w trybie do zapisu składowych - lewa strona operatora = //wywołanie metod w trybie do odczytu składowych - prawa strona operatora = odcieta() = p.odcieta();
rzedna() = p.rzedna();
promien = p.promien;
ile_kol++; }
kolo::~kolo() { ile_kol--;}
Przykład 2
Zrealizować klasę kolo do obsługi kół na płaszczyźnie na podstawie klasy punkt, uzupełniając dane o promień. Należy wykonać konstruktory: zwykły i kopiujący, z zastosowaniem listy argumentów, w obu klasach punkt i kolo.
...
#include "kolo5_1.h"
#include "punkt5_1.h"
void wyswietl(kolo&);
void wyswietl(punkt&);
void wyswietl(float);
void wyswietl(int, int);
void main() { clrscr();
{ wyswietl(kolo::liczba_kol(), kolo::info());
wyswietl(punkt::liczba_punktow(), punkt::info());
kolo k1(2, 2, 3), k2(1, 5, 6);
wyswietl(k1); wyswietl(k2);
wyswietl(kolo::liczba_kol(), kolo::info());
wyswietl(punkt::liczba_punktow(), punkt::info());
wyswietl(k1.odleglosc(k2)); .
/*kopiowanie obiektu k1 typu kolo za pomocą konstruktora kopiującego kola i punktu dzięki zastosowanej liście argumentów z jawnie wywołanym konstruktorem kopiującym punktu; utworzenie obiektu k3 typu kolo */
kolo k3 = k1;
wyswietl(k3);
}
wyswietl(kolo::liczba_kol(), kolo::info());
wyswietl(punkt::liczba_punktow(), punkt::info());
}...
#include "kolo5_1.h"
#include "punkt5_1.h"
kolo::kolo(float xx, float yy, float rr): promien(rr), punkt(xx, yy) { ile_kol++; }
kolo::kolo(kolo& p): punkt(p), promien(p.p_promien()) { ile_kol++; }
kolo::~kolo() { ile_kol--;}
3. Dziedziczenie metod i operatorów bez przedefiniowania (pokrywania) Przykład 3
W klasie bazowej punkt i klasie pochodnej kolo (przykład 2) wykonać:
a) konstruktory: zwykły i kopiujący za pomocą listy argumentów b) operator == jako funkcje zaprzyjaźniona w klasie punkt c) operator != jako metoda klasy punkt.
Operatory te powinny porównywać pola x i y w dwóch obiektach pochodzących z dowolnej klasy (punkt lub kolo).
W przypadku operatorów z b) i c) argument typu kolo jest poddany naturalnej konwersji do klasy punkt.
Stałe typu int są poddane konwersji konstruktorowej do klasy punkt w przypadku operatora b) zawsze, bo:
operator == (obiekt_klasy_punkt, obiekt_klasy_punkt), a w przypadku operatora c) tylko dla prawych argumentów, gdyż:
obiekt_klasy_punkt.operator != (obiekt_klasy_punkt):
b)wyswietl(6==punkt2,”6==punkt2”); ®
operator== (6, punkt2) orazwyswietl(8==kolo2,”8==kolo2”); ®
operator == (8, kolo2) ®poprawne!
c) wyswietl(6!=punkt2,"6!=punkt2 jest rowne ");® 6.operator != (punkt2)
oraz
wyswietl(8!=kolo2,"8!=kolo2 jest rowne ");® 8.operator != (kolo2); ® błędy!...
#include "kolo5_2.h"
#include "punkt5_2.h"
void wyswietl(kolo&);
void wyswietl(punkt&);
void wyswietl(float);
void wyswietl(int, char *);
void main()
{ kolo kolo1(2, 2, 3), kolo2(1, 5, 6); punkt punkt1 (2, 3), punkt2(2, 8);
wyswietl(kolo1); wyswietl(kolo2); wyswietl(punkt1); wyswietl(punkt2);
wyswietl(punkt1==punkt2, "\npunkt1==punkt2 jest rowne ");
wyswietl(kolo1==kolo2, "kolo1==kolo2 jest rowne ");
wyswietl(punkt1==kolo2, "punkt1==kolo2 jest rowne ");
wyswietl(6==punkt2, "6==punkt2 jest rowne ");
wyswietl(kolo2==8, "kolo2==8 jest rowne ");
wyswietl(punkt1==2, "punkt1==2 jest rowne ");
wyswietl(punkt1!=punkt2, "punkt1!=punkt2 jest rowne ");
wyswietl(kolo1!=kolo2, "kolo1!=kolo2 jest rowne ");
wyswietl(punkt1!=kolo2, "punkt1!=kolo2 jest rowne ");
// wyswietl(6!=punkt2, "6!=punkt2 jest rowne ");
// wyswietl(8!=kolo2," 8!=kolo2 jest rowne ");
wyswietl(punkt1!=2,"punkt1!=2 jest rowne ");}
class punkt // plik nagłówkowy punkt5_2.h { static int ile_punktow;
float x,y;
public: punkt (float = 0.0,float = 0.0);
punkt(punkt&);
~punkt();
void przesun (float, float);
float odleglosc(punkt&) const;
static int liczba_punktow();
static int info();
float& odcieta();
float& rzedna();
int operator!=(const punkt&);
friend int operator==(const punkt&, const punkt&);
};
#include "punkt5_2.h" //plik nagłówkowy kolo5_2.h class kolo:public punkt
{ static int ile_kol; //kolo posiada wszystkie pola klasy punkt oraz własne:
float promien; //ile_kol oraz promien public: kolo (float=0.0,float=0.0,float=0.0);
kolo(kolo&);
~kolo();
static int liczba_kol(); //dziedziczy wszystkie metody oprócz static int info(); //konstruktorów, destruktora oraz funkcji float& p_promien(); //zaprzyjaźnionej operator==
};
#include "punkt5_2.h" //plik punkt5_2.cpp z definicjami metod klasy punkt punkt::punkt(float xx, float yy) : x(xx),y(yy) { ile_punktow++; } punkt::punkt(punkt& p) : x(p.odcieta()), y(p.rzedna()) { ile_punktow++; }
float& punkt::odcieta() { return x;}
int punkt::operator!=(const punkt& p) { return !(*this==p); }
int operator ==(const punkt &p1, const punkt &p2)
{ return p1.x==p2.x && p1.y==p2.y;} //...
#include "kolo5_2.h" // plik kolo5_2.cpp z definicjami metod klasy kolo
#include "punkt5_2.h"
kolo::kolo(float xx, float yy, float rr): promien(rr), punkt(xx, yy) { ile_kol++; } kolo::kolo(kolo& p) : punkt(p), promien(p.p_promien()) { ile_kol++; } //...
4. Dziedziczenie metod i operatorów z przedefiniowaniem (pokrywaniem)
Przykład 4
Należy wykonać w klasach: bazowej punkt i pochodnej kolo operatory przedrostkowe i przyrostkowe: operator++ oraz operator--, dokonując przedefiniowania.
Metody te powinny zwiększać lub zmniejszać pola x i y w klasie punkt i dodatkowo pole promien w klasie kolo.
W definicji operatorów w klasie kolo wykorzystać metody-operatory dziedziczone z klasy punkt, np.
punkt::operator++();w definicji operatora ++
w klasie kolo.
...
#include "kolo5_3.h"
#include "punkt5_3.h"
void wyswietl(kolo&, char *napis);
void wyswietl(punkt&, char *napis);
void wyswietl(float);
void main() { clrscr();
{ kolo kolo1(2, 2, 3), kolo2(1, 5, 6);
punkt punkt1 (2, 3), punkt2(2, 8);
wyswietl(kolo1, "kolo1: "); wyswietl(kolo2, "kolo2: ");
wyswietl(punkt1, "punkt1: "); wyswietl(punkt2, "punkt2: ");
wyswietl(++kolo1, "++kolo1: "); wyswietl(++kolo2, "++kolo2: ");
wyswietl(++punkt1, "++punkt1: "); wyswietl(++punkt2, "++punkt2: ");
wyswietl(--kolo1, "--kolo1: "); wyswietl(--kolo2, "--kolo2: ");
wyswietl(--punkt1, "--punkt1: "); wyswietl(--punkt2, "--punkt2: ");
wyswietl(kolo1--, "kolo1--: "); wyswietl(kolo2--, "kolo2--: ");
wyswietl(punkt1--, "punkt1--: "); wyswietl(punkt2--, "punkt2--: ");
wyswietl(kolo1++, "kolo1++: "); wyswietl(kolo2++, "kolo2++: ");
wyswietl(punkt1++, "punkt1++: "); wyswietl(punkt2++, "punkt2++: ");
wyswietl(kolo1.odleglosc(kolo2));
float a = (kolo1--).odleglosc((kolo2++));
wyswietl(a);
wyswietl(kolo1.odleglosc(kolo2));
}}
class punkt //plik nagłówkowy punkt5_3.h klasy punkt { float x,y;
public: punkt (float = 0.0, float = 0.0);
punkt(punkt&);
~punkt();
punkt& operator++();
punkt& operator--();
punkt& operator++(int); //fikcyjny parametr dla przyrostkowego ++
punkt& operator--(int); // podobnie jak wyżej dla -- float odleglosc(punkt&) const;
static int info();
float& odcieta();
float& rzedna();};
#include "punkt5_3.h" //plik nagłówkowy kolo5_3.h klasy kolo class kolo : public punkt
{ float promien;
public: kolo (float = 0.0, float = 0.0,float = 0.0);
kolo(kolo&);
~kolo();
kolo& operator ++(); //pokrywanie metod operatorowych kolo& operator --();
kolo& operator ++(int); //fikcyjny operator dla przyrostkowego ++
kolo& operator --(int); //podobnie jak wyżej dla -- static int info();
float& p_promien();};
#include "punkt5_3.h" //plik punkt5_3.cpp z definicjami metod klasy punkt ...
punkt& punkt::operator++() { x += 1; y += 1; return *this; } punkt& punkt::operator++(int a) { x += 1; y += 1; return *this; }
#include "kolo5_3.h" //plik kolo5_3.cpp z definicjami metod klasy kolo
#include "punkt5_3.h"
...
kolo& kolo::operator ++()
{ punkt::operator++(); //wywołanie dziedziczonej metody
promien+=1;
return *this; }
kolo& kolo::operator ++(int)
{ punkt::operator++(3); //wywołanie dziedziczonej metody promien+=1;
return *this; }
5. Dziedziczenie klas z polami dynamicznymi - definicje konstruktorów
przypisania=, dziedziczenie metod bez/z przedefiniowaniem Przykład 5
Przykład prezentuje dziedziczenie metod i operatorów klas zawierających pole typu dynamiczna dwuwymiarowa tablica elementów typu int. Dotyczy on klasy bazowej figura (wykład4.doc/przykład 4) oraz klasy pochodnej figura_1, która odwzorowuje zakres indeksów tablicy Figura dla:
·
wierszy z 0 ¸ max_w do pocz_w ¸ pocz_w+max_w
·
kolumn z 0 ¸ max_kol do pocz_kol ¸ pocz_kol+max_kol.
Konstruktory klasy figura_1 należy zdefiniować za pomocą listy argumentów. Definiowanie destruktora w klasie figura_1 nie jest konieczne, gdyż pole dynamiczne Figura będzie zwolnione przez destruktor jawny klasy bazowej figura wywołany z destruktora domniemanego klasy pochodnej figura_1.
Klasę figura należy zmodyfikować następująco:
* zadeklarować składowe prywatne jako składowe protected
* zdefiniować operator= umożliwiający tworzenie kopii danych w obiekcie po lewej stronie operatora. Należy pamiętać, że domniemany operator przypisania kopiuje tylko zawartość obiektu, czyli w przypadku pól dynamicznych skopiuje jedynie ich adresy. Wtedy po przypisaniu dwa obiekty korzystają z tych samych pól dynamicznych. Pola dynamiczne obiektu lewego pozostaną w pamięci i będą niedostępne
W klasie figura_1 należy wprowadzić lub zmienić, korzystając z dziedziczenia:
* operator()(int, int), służący do indeksowania dwuwymiarowej tablicy Figura w odwzorowanym zakresie indeksów wierszy i kolumn,
* w metodzie przesun uwzględnić nowy zakres indeksów
·
oraz zadeklarować i zdefiniować operator=, pełniący podobną rolę do operatora = w klasie figura, gdyż operatory przypisania nie są dziedziczone.
Uwagi do programu:
1.konwersja obiektu wielokat do klasy bazowej figura i wywołanie operatora przeciążonego= z klasy figura, który kopiuje pole dynamiczne Figura;
domniemany operator= skopiowałby tylko część obiektu wielokat (część typu figura) do obiektu p; wówczas p i wielokat posiadałyby adres tej samej tablicy dynamicznej bez dostępu do tablicy obiektu p
2. błąd, gdy nie istnieje konwersja konstruktorowa figura_1::figura_1(figura), tworząca z obiektu p typu figura obiekt klasy figura_1
3.wywołanie operatora = z klasy figura_1, który kopiuje pole dynamiczne Figura;
domniemany operator = spełniłby rolę podobną jak w klasie figura (uwaga 1).
#include "fig5_4.h"
#include "fign5_4.h"
void wprowadz_punkty(figura_1&); //przekazanie przez referencje-zapis void wyswietl(const figura_1); //przekazanie przez wartość- odczyt void main()
{do
{ figura_1 wielokat(5,2,10,15), w(0,0,0) ; //...
figura p(5, 2);
p = wielokat; //uwaga 1
//wielokat = p;
//uwaga 2w = wielokat; //uwaga 3
cout<<"Nalezy wprowadzic wspolrzedne (x,y) roznych punktow\n";
//...
wprowadz_punkty(wielokat);
//...
wielokat.rysuj();
//...
wyswietl(wielokat);
//...
cout<<" Jesli koniec, nacisnil ESC, dalej - dowolny klawisz\n";
}while (getch() != 27);}
void wprowadz_punkty(figura_1& wielokat) {
int i = wielokat.podaj_p_w();
int jj = wielokat.podaj_p_k();
int ile_w = wielokat.podaj_w(), a;
int ile_kol = wielokat.podaj_k();
for (; i < ile_w; i++) //i już przypisane for (int j = jj; j < ile_kol; j++)
{ cout << "Podaj wielokat[" << i <<",”<< j << "]:= "; cin >> a;
wielokat << a; }}
void wyswietl(const figura_1 wielokat) {
int i = wielokat.podaj_p_w();
int jj = wielokat.podaj_p_k();
int ile_w = wielokat.podaj_w();
int ile_kol = wielokat.podaj_k(); //...
for (; i < ile_w; i++) //i już przypisane { for(int j = jj; j < ile_kol; j++)
//referencyjny operator() na kopii obiektu przekazanego przez wartość
cout<<'\n';}}
class figura //plik nagłówkowy fig5_4.h klasy bazowej figura {
protected: int ile;
int max_w;
int max_kol;
int* Figura;
void kopia(const figura&) int koniec(int,int) const;
public: figura (int = 0, int=0);
figura(figura&);
~figura();
void przesun (int, int, int);
void rysuj() const;
int podaj_wsp_x() const;
int podaj_wsp_y() const;
int podaj_ile() const;
figura& operator<<(int);
int& operator()(int, int) const;
figura& operator=(const figura&);
};
#include "fig5_4.h" //plik nagłówkowy klasy pochodnej figura_1
class figura_1: public figura {
int pocz_w; //indeksy początkowe wierszy i kolumn
int pocz_kol; //czyli dodatkowe składowe
public:
figura_1 (int = 0, int = 0, int = 0, int = 0);
figura_1(figura_1&);
~figura_1(); //nie jest konieczny- nie ma nowych pól dynamicznych void przesun (int, int, int); //metoda pokryta
int podaj_p_w() const; //nowe metody dotępu do nowych pól int podaj_p_k() const;
int podaj_w() const; //nowe metody wyznaczające liczbę wierszy i kolumn int podaj_k() const; //np. pocz_kol+max_kol
int& operator()(int, int) const; //operator pokryty
figura_1& operator=(const figura_1&); //operator pokryty bez dziedziczenia };
#include "fig5_4.h" //plik fig5_4.cpp z definicjami metod klasy figura
... // metody zaprezentowane w pliku wyklad5.doc, punkt 3 void figura::kopia(const figura& p) // metoda do kopiowania pól klasy figura { if (coreleft() < p.max_w*p.max_kol*sizeof(int)) exit(1);
ile = 0;
max_w = p.max_w;
max_kol = p.max_kol;
Figura = new int [max_w*max_kol];
for (int i=0; i<max_w; i++) for (int j=0; j<max_kol; j++) *this << p(i, j); }
figura::figura(figura& p) { kopia(p); } figura& figura::operator= (const figura& p) { cout<<"operator przypisania figura\n";
if (this != &p) //przypisywane, gdy różne obiekty klasy figura { delete Figura; //usuwa się tablice w obiekcie po lewej stronie kopia(p); } //operatora przypisania i tworzy kopie tablicy
return (*this); } //z obiektu po prawej stronie instrukcji przypisania
#include "fign5_4.h" // plik fign5_4.cpp z definicjami metod klasy figura_1 ...
figura_1::figura_1 (int xx, int w, int k) : figura(xx), pocz_w(w), pocz_kol(k) { } figura_1::figura_1(figura_1&p) : figura(p),
pocz_w(p.pocz_w),pocz_kol(p.pocz_kol) { } void figura_1::przesun (int d, int ile_w, int ile_kol)
{ figura :: przesun(d, ile_w-pocz_w, ile_kol-pocz_kol); } int& figura_1::operator()(int ile_w, int ile_kol) const
{ return figura :: operator() (ile_w-pocz_w, ile_kol-pocz_kol); } figura_1 & figura_1::operator= (const figura_1& p)
{
if (this != &p) //przypisywane, gdy różne obiekty klasy figura_1 { delete Figura; //usuwa się tablice w obiekcie this po lewej stronie
kopia(p); //operatora przypisania i tworzy kopie tablicy z obiektu p } // przekształconego do klasy figura po prawej stronie instrukcji przypisania pocz_w = p.pocz_w;
pocz_kol = p.pocz_kol;
return (*this); }