Wykład 6
1. Obiekty z dynamicznymi polami typu jednowymiarowa tablica elementów typu struktura. Przeciążanie operatorów: << , >>, []
2. Obiekty z dynamicznymi polami typu dwuwymiarowa tablica elementów typu int- przeciążanie operatora << na rzecz dowolnej klasy oraz operatora wywołania funkcji ()
3. Konwersje typów definiowane przez użytkownika - przeciążanie operatora rzutowania operator typ ()
4. Konwersje typów definiowane przez użytkownika - konwersje z użyciem jednoargumentowych konstruktorów
1. Obiekty z dynamicznymi polami typu jednowymiarowa tablica elementów typu struktura. Przeciążanie operatorów: << , >>, []
Przykład 6.1
Program w przykładzie 6.1 wprowadza i wyświetla współrzędne wierzchołków wielokąta oraz rysuje wierzchołki w postaci znaków ¦ w miejscach o podanych współrzędnych. Wielokąt jest zawarty w klasie figura, o maksymalnej liczbie wierzchołków określonej liczbą max.
Obiekt typu figura powinien zawierać:
konstruktor zwykły tworzący dynamiczną tablice struktur Figura zawierających współrzędne wierzchołków (x, y); konstruktor kopiujący tworzący dynamiczną tablicę struktur Figura i kopiujący zawartość przekazywanego obiektu oraz destruktor usuwający tę tablicę
metodę rysuj, wyświetlającą znak ¦ na ekranie w miejscu (x, y), wtedy gdy znajduje się w obrębie ekranu (1<= x <=80, 1 <=y<=25). Dane każdego wierzchołka pobiera z dynamicznej tablicy struktur Figura.
metodę przesun, zmieniającą współrzędne x o dx i y o dy wybranego elementu - wierzchołka z tablicy Figura
dwa przeciążone operatory indeksowania: jeden do odczytu i drugi do zapisu wartości x i y wybranego i-tego elementu - wierzchołka z tablicy Figura
operator przeciążony >> jako funkcję zaprzyjaźnioną, której lewym argumentem jest obiekt klasy istream, a prawym jest referencja do struktury typu wsp, zdefiniowanego jako prywatny typ klasy figura. Wykorzystanie tej definicji poza blokiem deklaracji klasy jest możliwe dzięki następującej deklaracji
figura::wsp.
W przypadku, gdy struktura typu wsp jest deklaracją public, można stosować nazwę wsp bezpośrednio. Operator przeciążony >> jest wykorzystany do zapisu danych do tablicy struktur Figura, umieszczonej w klasie figura.
operator przeciążony << jako funkcja zaprzyjaźniona, której lewym argumentem jest obiekt klasy ostream, a prawym jest struktura typu wsp, zdefiniowanego jako prywatny typ klasy figura.
Operator przeciążony << jest wykorzystany do odczytu danych z tablicy struktur Figura, umieszczonej w klasie figura.
metoda koniec do sprawdzenia, czy jest wolne miejsce w tablicy
Należy zabezpieczyć metody przed dostępem do elementów tablicy Figura poza jej ograniczającymi indeksami 0-(max-1) za pomocą metody koniec.
...
#include "fig4_3.h"
void wprowadz_punkty(figura&);
void wyswietl(const figura);
void main() { do
{figura wielokat(5);
wprowadz_punkty(wielokat); //sposób wprowadzania obojętny dla klasy wielokat.rysuj(); //operacja powierzona klasie
wyswietl(wielokat); // operacja poza obowiązkami klasy } while (getch() != 27);}
void wprowadz_punkty(figura& wielokat) { int ile = wielokat.podaj_wsp();
for (int i = 0; i < ile; i++)
{cout<< "Podaj wspolrzedne x, y dla wielokat["<<i<<"]: ";
cin >> wielokat[i];
clrscr();}}
void wyswietl(const figura wielokat) { int ile = wielokat.podaj_wsp();
for (int i = 0; i < ile ; i++)
cout<< setw(15)<<"Wielokat["<<i<<"] "<<
setw(5)<<wielokat[i]<<endl;}
class figura //plik nagłówkowy fig4_3.h
{ struct wsp {int x, y;};
int max; // maksymalna liczba współrzędnych w tablicy dynamicznej Figura wsp* Figura; //wskaźnik zgodny z tablicą struktur
int koniec(int) const;
public: figura (int = 1);
figura(figura&);
~figura();
void przesun (int, int, int);
void rysuj() const;
int podaj_wsp() const;
wsp operator[](int) const;
wsp& operator[](int);
friend istream& operator>>(istream&, wsp&);
friend ostream& operator<<(ostream&, const wsp);
#include "fig4_3.h" //plik z definicjami metod fig4_3.h ...
figura::figura (int xx)
{if (coreleft() < xx*sizeof(wsp)) exit(1);
else
{max = xx;
Figura = new wsp [max];}}
figura::figura (figura& p)
{ if (coreleft() < p.max*sizeof(wsp)) exit(1);
else
{ max = p.max;
Figura = new wsp [max];
for (int i = 0; i < max; i++) Figura[i] = p[i]; } }
figura::~figura() { delete [] Figura; } int figura::koniec(int ile) const {return ile >=0 && ile<max; }
void figura::przesun (int dx, int dy, int ile) { if (koniec(ile))
{ Figura[ile].x += dx;
Figura[ile].y += dy; } }
istream& operator>>(istream& a, figura::wsp& b) { a >> b.x >> b.y;
return a;}
ostream& operator<< (ostream& a, const figura::wsp b) { a << b.x << setw(5)<< b.y;
return a;}
figura::wsp figura::operator[](int ile) const {if (koniec(ile))
return Figura[ile];
return Figura[0]; }
figura::wsp& figura::operator[](int ile) {if (koniec(ile))
return Figura[ile];
return Figura[0]; }
2. Obiekty z dynamicznymi polami typu dwuwymiarowa tablica elementów typu int- przeciążanie operatora << na rzecz dowolnej klasy oraz operatora wywołania funkcji ()
Przykład 6.2
Klasa figura realizuje te same czynności, co klasa figura z przykładu 6.1, lecz jest wykonana w inny sposób:
tablica Figura jest dynamiczną tablicą o elementach typu int, traktowaną jako tablica dwuwymiarowa o liczbie wierszy max_w oraz liczbie kolumn max_kol.
Pole ile przechowuje liczbę aktualnie wprowadzonych współrzędnych.
Zastosowanie jednowymiarowej tablicy pozwala na elastyczny podział na dwa wymiary, gdzie wiersze reprezentują liczbę wierzchołków wielokąta, natomiast kolumny określają liczbę wspólrzędnych wierzchołków.
wykonano operator <<, gdzie lewy argument jest obiektem klasy figura, a prawym argument typu int (kolejne współrzędne). Wynikiem działania operatora, wykonanego jako metoda, jest referencja do lewego argumentu, czyli obiektu wywołującego metodę. Operator ten zastosowano do zapisu współrzędnych wierzchołków wielokąta do tablicy Figura.
zamiast metod dostępu do współrzędnych np. odcieta(int) i rzedna(int) przeciążono operator wywołania funkcji operator()(int, int) jako metodę, zastępujący indeksowanie [][] w tablicy dwuwymiarowej, niemożliwy do przeciążenia w C++ (można przeciążać tylko operator [] dwuargumentowy, gdzie lewym argumentem jest obiekt, a prawym indeks - tabela, wykład 4) Operator wykorzystano do czytania współrzędnych wierzchołków wielokąta, umieszczonych w tablicy Figura.
Należy zabezpieczyć metody przed dostępem do elementów tablicy Figura poza jej ograniczającymi indeksami 0 <= indeks < max_w *max_kol.
...
#include "fig4_4.h"
void wprowadz_punkty(figura&);
void wyswietl(const figura);
void main() {do
{ figura wielokat(5, 2);
wprowadz_punkty(wielokat);
wielokat.rysuj();
wyswietl(wielokat);
} while (getch() != 27); }
void wprowadz_punkty(figura& wielokat) { int ile_w = wielokat.podaj_wsp_x(), a;
int ile_kol = wielokat.podaj_wsp_y();
for (int i = 0; i < ile_w; i++) for int j = 0; j < ile_kol; j++)
{ cout << "Podaj wielokat[" << i <<",”<< j << "]:= "; cin >> a;
wielokat << a; }}
void wyswietl(const figura wielokat) { int ile_w = wielokat.podaj_wsp_x();
int ile_kol = wielokat.podaj_wsp_y();
for (int i = 0; i < ile_w; i++) {for int j = 0; j < ile_kol; j++)
cout << setw(15) << "Wielokat[" << i << "," << j << "] " <<
setw(5) << wielokat(i, j);
cout<<'\n';}}
class figura
//plik nagłówkowy fig. 4_4.h {int max_w, max_kol, ile;
int* Figura;
int koniec(int, int) const;
public: figura (int = 1, int = 2);
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; } ;
#include "fig4_4.h" //plik z definicjami metod fig4_4.cpp ...
figura::figura (int xx, int yy)
{ if (coreleft() < xx*yy*sizeof(int)) exit(1);
else { ile = 0;
max_w = xx;
max_kol = yy
Figura = new int [max_w*max_kol]; } } figura::figura(figura& p)
{if (coreleft() < p.max_w*max_kol*sizeof(int)) exit(1);
else
{ 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[i*max_kol+j] = p(i, j);
int figura::koniec(int ile_w, int ile_kol) const
{return ile_w >=0 && ile_w<max_w && ile_kol>=0 && ile_kol<max_kol; }
figura& figura::operator<<(int xx) { if (ile < max_w*max_kol) Figura[ile++] = xx;
return (*this); }
int figura::operator()(int ile_w, int ile_kol) const {if (koniec(ile_w, ile_kol))
return Figura[ile_w*max_kol + ile_kol];
return Figura[0]; }
3. Konwersje typów definiowane przez użytkownika - przeciążanie operatora rzutowania operator typ ()
Dwa rodzaje funkcji, obowiązkowo metod (tabela z wykładu 4) umożliwiają zdefiniowanie konwersji przez użytkownika:
konstruktory jednoargumentowe (niezależnie od rodzaju argumentu) przekształcają typ argumentu do typu klasy, do której należą
operatory rzutu do danego typu typ, który może być klasą lub typem podstawowym: operator typ (). Operatory te nie wymagają podania typu zwracanego wyniku. W wyniku rzutu obiekt danej klasy jest przekształcany do typu typ
Reguły do wyboru konwersji są zbliżone do reguł stosowanych przy wywoływaniu przeciążonych funkcji:
konwersje definiowane przez użytkownika są używane tylko wtedy, kiedy jest to niezbędne
w jednym ciągu przekształceń (argumentu funkcji lub operatora) może być użyta tylko jedna konwersja definiowana prze użytkownika
nie może wystąpić wiele ciągów przekształceń prowadzących do tego samego typu
Przykład 6.3
Wykonano przeciążony operator konwersji operator int() dla klasy punkt. Ciąg przekształceń musi być jednoznaczny. Gdyby przeciążono operator double(), wtedy w przypadku wyrażeń liczba_c=p1+1.25, liczba_r=p1+1,25 byłoby:
pierwszy ciąg przekształceń: punkt do int, int do double
drugi ciąg: punkt do double
#include "punkt4_5.h"
...
void wyswietl(int,char []); // 1-a funkcja prezentująca konwersję punkt do int void wyswietl(double,char []); // 2-a funkcja prezentująca konwersję punkt do int void main()
{ {punkt p1(2,2), p2(1,5);
int liczba_c;
double liczba_r;
liczba_c = p1; // p1 do int, int=int
liczba_c = p2; //p2 do int, int=int
wyswietl(p1, s2); //p1 do int, 1-a wyswietl
wyswietl(p2, s2); //p2 do int, 1-a wyswietl
liczba_c = p1+10; //p1 do int, int+int i int =
int
wyswietl(p2+10, s2); //p2 do int, int+int i do 1-a wyswietl liczba_c = p1 + p2; //p1 do int i p2 do int, int+int, int=int wyswietl(liczba_r = p1, s3); //p1 do int, double=int, 2-a wyswietl liczba_r = p1 + 10; //p1 do int, int+int, double=int liczba_r = p1 + p2; //p1 do int, p2 do int, int+int, double=int liczba_c = p1 + 1.25; //p1 do int, int + double, int=double liczba_r = p1 + 1.25; //p1 do int, int + double, double=int
liczba_r = p1; //p1 do int, double=int
} }
void wyswietl(int w, char napis[]) { cout <<napis << w << ’\n’; getch(); } void wyswietl(double w, char napis[]) { cout <<napis << w << ’\n’; getch(); } class punkt
//plik nagłówkowy punkt4_5.h { .... public:...
operator int();}; //operator konwersji obiektu klasy punkt do typu int,
punkt::operator int () { return x + y; } // operator rzutowania int()
4. Konwersje typów definiowane przez użytkownika - konwersje z użyciem jednoargumentowych konstruktorów
Przykład 6.4
Zastosowano konwersję za pomocą konstruktora jednoargumentowego typu int do klasy punkt. Wykonano przeciążony operator+ za pomocą funkcji zaprzyjaźnionej. Ciąg przekształceń musi być jednoznaczny.
...
#include "punkt4_6.h"
void wyswietl(punkt, char[]); // funkcja demonstrująca konwersję za pomocą //konstruktora
void main()
{ punkt p1(2, 2), p2(1, 5);
wyswietl(6, s2); // int do punkt (6,0) za pomocą konstruktora
wyswietl(9.9, s2); //float do int, int do punkt (9,0) za pomocą konstruktora p1 = 7; //int do punkt (7,0) za pomocą konstruktora-
//punkt tymczasowy przypisany do p1 i usunięty z wyw. destruktora p2 = 8.8; //double do int (8), int do punkt (8,0) za pomocą
// konstruktora -punkt tymczasowy przypisany do p1 i usunięty p1 = p2 +6; //6 do punkt za pomocą jednoargumentowego konstruktora oraz
//dodawanie p1=operator+(p2, 6)
p1 = 6 + p2; //6 do punkt za pomocą jednoargumentowego konstruktora oraz //dodawanie p1=operator(6, p2); działanie byłoby odrzucone przez kompilator przy //realizacji operatora za pomocą metody, gdyż nie można wywołać 6.operator+(p2) }
void wyswietl(punkt p, char napis[])
{ cout <<napis<< p.odcieta() << " "<< p.rzedna() << ’\n’; getch();}...
//plik nagłówkowy punkt5_5.h class punkt
{ ...
public: punkt (int=0,int=0);
friend punkt operator +(punkt, punkt);
...};
//plik punkt5_5.cpp z definicjami metod
#include "punkt5_5.h"
...
punkt::punkt(int xx, int yy) { x = xx; y = yy; ile_punktow++; } punkt operator+(punkt p1, punkt p2)
{ return (p1.x + p2.x, p1.y + p2.y); }...