Both sides previous revision
Poprzednia wersja
Nowa wersja
|
Poprzednia wersja
|
pl:dydaktyka:jimp2:2017:labs:operatory [2017/04/04 02:07] mwp [Konwersja typów] |
pl:dydaktyka:jimp2:2017:labs:operatory [2019/06/27 15:50] (aktualna) |
//dostępu do prywatnych pól z wewnątrz definicji | //dostępu do prywatnych pól z wewnątrz definicji |
//funkcji zadeklarowanej poniżej | //funkcji zadeklarowanej poniżej |
// friend std::istream& operator>>(std::istream &, Punkt&); | // friend std::istream& operator>>(std::istream &, Point&); |
... | ... |
| |
| |
using ::std::istream; | using ::std::istream; |
| using ::std::ws; |
| |
//Helper functions: | //Helper functions: |
void CheckNextChar(char c, istream *is) { | void CheckNextChar(char c, istream* is) { |
int next_char = is.peek(); | int next_char = is->peek(); |
if (next_char != c) { | if (next_char != c) { |
throw runtime_error("invalid character"); | throw runtime_error("invalid character"); |
} | } |
is.ignore(); | is->ignore(); |
} | } |
| |
void IgnoreWhitespace(istream *is) { | void IgnoreWhitespace(istream* is) { |
is >> ws; | (*is) >> ws; |
} | } |
| |
double ReadNumber(istream *is) { | double ReadNumber(istream* is) { |
double d; | double d; |
is >> d; | (*is) >> d; |
return d; | return d; |
} | } |
//wewnątrz funkcji (STL nie używa naszej konwencji z przekazywaniem | //wewnątrz funkcji (STL nie używa naszej konwencji z przekazywaniem |
//przez wskaźnik) | //przez wskaźnik) |
istream& operator>>(istream & input, Punkt& p){ | istream& operator>>(istream & input, Point& p){ |
CheckNextChar('(', &input); | CheckNextChar('(', &input); |
p.SetX(ReadNumber(&input)); | p.SetX(ReadNumber(&input)); |
|.|.*|::|?:|sizeof| | |.|.*|::|?:|sizeof| |
| |
| ===== Czy przeciążyć operator ===== |
| |
| Zasadniczo jeśli zastosowanie operatora w kodzie używającym danego obiektu (wywołującym metody) jest czytelne, jednoznaczne i intuicyjne wtedy można rozważyć przeciążenie operatora dla danego typu. W przeciwnym wypadku nie należy na siłę deklarować kodu operatorów, gdyż pogorszą one tylko jakość i czytelność kodu. |
| |
| ===== Dodatkowy rozszerzony opis ===== |
| |
| Zapoznać się z opisem na stronie [[http://en.cppreference.com/w/cpp/language/operators|Operatory]]. Na tej stronie są dodatkowe przykłady. |
======Ćwiczenia====== | ======Ćwiczenia====== |
- [1 plus] Przetestować operator wczytywania dla klasy Punkt i dopisz operator wypisania ("<<"). Sprawdź w jakich przypadkach ten operator się wywołuje. | - [1 plus] Przetestować operator wczytywania dla klasy Point i dopisać operator wypisania ("<<"). Sprawdzić w jakich przypadkach ten operator się wywołuje. (Przetestować zarówno na cout, cin, jak i stringstream). |
- Do klasy tablica dynamiczna DTab (z laboratorium [[.:klasy1|Klasy i obiekty I]]): | - Napisać klasę Student z polami id, first_name, last_name, program, year, gdzie wszystkie pola poza year są typu string, a pole year ma własny typ StudyYear. |
- [1 plus] dopisz operator '[]' pozwalający na pobranie danego elementu tablicy za pomocą konstrukcji <code cpp>DTab d(10); | - [1 plus] zdefiniować operator %%++%% i %%--%% pre(in|de)krementacji dla StudyYear |
cout << d[5] << endl;</code> | - [2 plus] zdefiniować operator << i >> zapisu i odczytu ze strumienia, przy następujących formatach: |
- [1 plus] Jak zrobić żeby dało się ustawić element tablicy za pomocą tego operatora, a nie tylko go pobrać?:<code cpp>tab[2] = 7; //ustawia 2 element tablicy na wartość 7</code> | * StudyYear - 2 |
- [1 plus] dopisz operator przypisania ( = ) | * Student - Student {id: "2030001234", first_name: "Arkadiusz", last_name: "Kowalski", program: "informatyka", year: 2} |
- [1 plus] dopisz operatory << i >>. Przyjmij format pobierania tablicy jako <code>[1,2,3,4]</code> | * StudentRepository - [Student {id: "203000001",... , Student {id: "...] |
- [1 plus] dopisz operator <nowiki>++</nowiki> umożliwiający rozszerzenie tablicy o 1 | - [1 plus] zdefiniować operator == porównywania dla StudyYear, Student i StudentRepository i < dla StudyYear |
- [1 plus] Wykorzystując klasę //Matrix// napisz dla klasy //Complex// operator rzutowania:<code cpp>Complex c("5i3"); | - [1 plus] zdefiniować operator '[]' zakresu pozwalający na pobranie z repozytorium studenta o określonym id |
Matrix nowa = (Matrix)c; | - [1 plus] co należy zrobić z powyższym operatorem, żeby była możliwa operacja <code cpp>repository["201500022324"].ChangeFirstName("Ziemowit");</code> i została zmienione imię studenta już w repozytorium. |
</code> | - [1 plus] dopisz operator rzutowania dla StudyYear do typu int. |
- **[5 punktów] Napisz klasę Mapa, która będzie zawierać listę obiektów typu Para. Klasa Para powinna posiadać dwa pola jedno typu //string// a drugie typu //integer//. Klasa Mapa powinna mieć konstruktor przyjmujący jako parametr ścieżkę do pliku tekstowego. W konstruktorze powinno nastąpić odczytanie pliku i zbudowanie indeksu wyrazów, tak aby każdy wyraz z pliku miał odpowiadający sobie obiekt klasy Para w liście. Pole typu //string// wewnątrz obiektów Para powinno odpowiadać danemu słowu, natomiast pole typu //integer// ilości powtórzeń tego słowa we wczytanym pliku. Plik jest __dowolnym plikiem tekstowym!__ Analizując go, ignorujemy znaki interpunkcyjne, spacje tabulatory, etc. i wczytujemy tylko słowa. ** | - [2 plusy] Zdefiniować klasę Zipper ze statyczną metodą zip(std::vector<std::string>, std::vector<int>), która pozwoli na uruchomienie następującego kodu: <code cpp>int foo(const vector<string> &v1, const vector<int> &v2) { |
* Przeładuj operator klasy Mapa **[]** tak aby możliwe było poniższe wywołanie:<code cpp>Mapa m("myfile,txt"); | for (const pair<string,int> &p : Zipper::zip(v1,v2)) { |
// w zmiennej ilosc powinna znaleźć się ilość powtórzeń | if (p.first == "elo") { |
| return p.second+4; |
| } |
| } |
| return 0; |
| }</code> Podpowiedź: udostępniona też [[http://coliru.stacked-crooked.com/a/ff24fd32a47a6e18|TU]] <code cpp>#include <iostream> |
| #include <string> |
| #include <vector> |
| #include <utility> |
| |
| using std::cout; |
| using std::endl; |
| using std::vector; |
| using std::string; |
| using std::pair; |
| using std::literals::string_literals::operator""s; |
| |
| |
| class ZipperIterator { |
| public: |
| pair<string,int> operator*() const; //wmagane w linii 74 |
| ZipperIterator &operator++(); //wymagane w linii 73 for(_;_;TU) |
| bool operator!=(const ZipperIterator &other) const; //wymagane w linii 73 for(_;TU;_) |
| private: |
| //TODO |
| }; |
| |
| //umożliwia przeglądanie dwóch wektorów na raz, w jednej pętli range-for |
| class Zipper { |
| public: |
| static Zipper zip(const vector<string> &vs, const vector<int> &vi); |
| |
| ZipperIterator begin(); //wymagane w linii 73 for(TU;_;_) |
| ZipperIterator end(); //wymagane w linii 73 for(_;TU;_) |
| private: |
| //TODO |
| }; |
| |
| |
| |
| int main() |
| { |
| vector<int> vi = {1,2,3}; |
| vector<string> vs = {"one"s,"two"s,"three"s}; |
| |
| //PROSTY przykład |
| for (const auto i : vi) { |
| cout << i; |
| } |
| cout << endl; |
| //to samo bez auto: |
| for (const int i : vi) { |
| cout << i; |
| } |
| cout << endl; |
| //przetłumaczony powyższa petla mniej wiecej tak jak to kompilator |
| //rozumie: |
| for (vector<int>::iterator it = vi.begin(); it != vi.end(); ++it) { |
| const int i = *it; |
| cout << i; |
| } |
| cout << endl; |
| |
| //Przykład z zipperem |
| for (const auto &p : Zipper::zip(vs,vi)) { |
| cout << p.second << " is " << p.first; |
| } |
| cout << endl; |
| //to samo bez auto: |
| for (const pair<string,int> &p : Zipper::zip(vs,vi)) { |
| cout << p.second << " is " << p.first; |
| } |
| cout << endl; |
| |
| //przetłumaczony powyższa petla mniej wiecej tak jak to kompilator |
| //rozumie: |
| Zipper tmp = Zipper::zip(vs,vi); |
| for (ZipperIterator it = tmp.begin(); it != tmp.end(); ++it) { |
| const pair<string,int> &p = *it; |
| cout << p.second << " is " << p.first; |
| } |
| cout << endl; |
| }</code> |
| |
| - **[5 punktów] Napisz klasę WordCounter (podobne ćwiczenie było już tylko jako struktura z języka C, tym razem ma być to pełna klasa z C%%++%%), która będzie zawierać licznik słów. Należy zdefiniować klasę Word, która będzie stanowiła klucz (słowo zliczane) i klasę Counts, która będzie przechowywała liczbę zliczeń. Zarówno klasa Word i Counts powinna zawierać pojedynczy typ prymitywny. Klasa WordCounter powinna mieć konstruktor domyślny inicjalizujący pusty słownik i konstruktor z listą inicjalizacyjną pozwalający zliczyć podane słowa. Dodatkowo należy zdefiniować statyczną funkcję FromInputStream przyjmującą jako parametr istream pokazujący na tekst. W funkcji FromInputStream powinno nastąpić odczytanie tekstu i zbudowanie indeksu wyrazów, tak aby każdy wyraz z pliku miał odpowiadający sobie obiekt std::pair<Word,Counts> w dowolnym kontenerze c%%++%%. Pole typu //string// wewnątrz obiektów Word powinno odpowiadać danemu słowu, natomiast pole typu //integer// wewnątrz Counts ilości powtórzeń tego słowa w wewnętrznym słowniku. Zawartość strumienia jest __dowolnym tekstem!__ Analizując go, ignorujemy znaki interpunkcyjne, spacje tabulatory, etc. i wczytujemy tylko słowa. ** |
| * Przeładuj operator klasy WordCounter **[]** tak aby możliwe było poniższe wywołanie:<code cpp>std::ifstream is ("myfile.txt"); |
| WordCounter wc = WordCounter.FromInputStream(&is); |
| // w zmiennej ilość powinna znaleźć się ilość powtórzeń |
// słowa "programowanie" w pliku "myfile.txt" | // słowa "programowanie" w pliku "myfile.txt" |
int ilosc = m["programowanie"];</code> | int ilosc = wc["programowanie"];</code> |
* Przeładuj operator **%%<<%%** dla klasy Mapa, aby możliwe było wyświetlenie raportu o ilości słów i ich liczebności w danym pliku. Dane wyświetlane powinny być posortowane malejąco. Do tego celu wykorzystaj metodę //[[http://www.cplusplus.com/reference/list/list/sort/|sort]]// klasy //list// - wykorzystaj listę z biblioteki standardowej!. | * Przeładuj operator **%%<<%%** dla klasy WordCounter, aby możliwe było wyświetlenie raportu o ilości słów i ich liczebności w danym pliku. Dane wyświetlane powinny być posortowane malejąco. Do tego celu wykorzystaj metodę //[[http://en.cppreference.com/w/cpp/algorithm/sort|sort]]// z biblioteki //algorithm// - wykorzystaj dowolny kontener z biblioteki standardowej! (w dokumentacji w przykładzie na dole jest przykład jak użyć dowolnego warunku porównującego w konteście sortowania, zerknąć na przykład środkowy z użyciem struktury customLess). |
* Przeładuj operatory porównania (//<,>,==//) i przypisania (//=//) dla klasy Para (porównywanie względem liczebności). | * Przeładuj operatory porównania (//<,>,==//) dla klasy Counts (porównywanie względem liczebności). |
* Przeładuj operator **%%++%%** dla klasy Para, tak aby można było szybko inkrementować liczebność danego słowa podczas budowania mapy. | * Przeładuj operator **%%++%%** dla klasy Counts, tak aby można było szybko inkrementować liczebność danego słowa podczas budowania licznika. |
| * Zdefiniuj funkcje DistinctWords zwaracającą ilość różnych słów w liczniku |
| * Zdefiniuj funkcje TotalWords zwaracającą ilość słów w liczniku z uwzględnieniem ich liczności (DistinctWords <= TotalWords) |
| * Zdefiniuj funkcje Words zwarającą zbiór wszystkich słów w liczniku |
| |