Advertisement
Guest User

Untitled

a guest
May 20th, 2016
237
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.27 KB | None | 0 0
  1. 6. Metody część 2
  2.  
  3. W tym rozdziale powiemy sobie więcej o metodach. Zrozumienie tego rodziału jest kluczowe do pisania ładnego i przyjrzystego kodu.
  4.  
  5. 6.1 Przekazywanie argumentów do funkcji
  6.  
  7. Przeważnie pisaliśmy metody na zasadzie
  8.  
  9. void Method(){}
  10.  
  11. W nawiasach () możemy przekazać argumenty do funkcji. Już wyjaśniam, dlaczego jest to przydatne. Funkcje tak samo jak klasy, powinny trzymać się zasady Single Responsibility Principle.
  12. Jeżeli piszemy kalkulator i zrobimy klase CalculatorLogic na takiej zasadzie
  13.  
  14. CalculatorLogic()
  15. {
  16. public:
  17. CalculatorLogic(){}
  18. };
  19.  
  20. Powstaje pytanie jak przekazywać dane do tej klasy? Na przykładzie:
  21.  
  22. void Add()
  23. {
  24. int firstNumber, secondNumber;
  25. cout << "podaj dwie liczby calkowite\n";
  26. cin >> firstNumber >> secondNumber;
  27. cout << "Twoj wynik to " << firstNumber + secondNumber << "\n";
  28. }
  29.  
  30. Zastanów się co jest źle z tym kodem zanim zaczniesz czytać dalej.
  31. - Funkcja nazywa się Add, a pobiera i wyświetla coś użytkownikowi! Jest to złamanie SRP, a co więcej jest to bardzo niepraktyczne. Dlaczego? Powiedzmy, że chcemy zrobić sprawdzenie liczb czy są poprawne (np zakres, czy ktoś nie wprowadził znaku itd.). Funkcja wtedy po prostu zrobi się skomplikowana. A takie funkcje (przeważnie) nie powinny istnieć.
  32.  
  33. Przychodzą nam z pomocą parametry funkcji. Popatrz na przykładowy kod
  34.  
  35. void Add(int firstNumber, int secondNumber)
  36. {
  37. cout << "Twoj wynik to " << firstNumber + secondNumber << "\n";
  38. }
  39.  
  40. Kod nam się skrócił o rząd wielkości. Zrobił się protszy i czytelniejszy. Nadal wyświetla coś do użytkownika. Tym zajmiemy się w sekcji 6.2.
  41. Jak wywołujemy taką funkcje? Robimy coś na zasadzie:
  42.  
  43. int main()
  44. {
  45. int numberOne, numberTwo; // specjalnie zmienilem tutaj nazwy, bo chce Ci pokazac, ze nazwy w funkcji są niezalezne. One mają swoj wlasny proces zycia (swoj wlasny zasieg ktory jest tylko i wylacznie w tej funkcji*)
  46. cout << "podaj dwie liczby calkowite\n";
  47. cin >> numberOne >> numberTwo;
  48.  
  49. CalculatorLogic calculatorLogic;
  50. calculatorLogic.Add(numberOne, numberTwo);
  51. }
  52.  
  53. Jak widać, ilość argumentów przekazanych i zdefiniowanych musi się zgadzać. Spróbuj skompilować kod z jednym przekazanym argumentem (np. tylko numberOne). Kompilator powinien nam podpowiedzieć, że funkcja oczekuje X argumentów a podaliśmy Y argumentów.
  54. Zdefiniowane argumenty mogą być dowolnego typu, ale przekazane obiekty muszą się zgadzać jeżeli chodzi o typy danych. Troche to pogmatwane. Rozbijmy to na części pierwsze
  55.  
  56. Jeżeli mamy funkcje
  57. void Foo(Wood object) {}
  58.  
  59. To nie możemy jej wywołać z obiektem typu Metal*. Typy danych muszą się zgadzać inaczej program nam się nie skompiluję. Jeżeli chodzi o liczby, to uważaj by do inta nie przepisywać float'ów. Wszystko co jest po przecinku zostanie **ucięte**!
  60.  
  61. 6.2 Zwracany typ funkcji
  62.  
  63. W większości wypadków pisaliśmy void NazwaFunkcji(argumenty). Teraz wyjaśnie co robi ten void i jak go zamienić. Popatrz na ten kod
  64.  
  65. int Add(int firstNumber, int secondNumber)
  66. {
  67. return firstNumber + secondNumber;
  68. }
  69.  
  70. Zmieniłem deklaracje z void na int. To mówi, że ta funkcja zwraca jako wynik liczbę całkowitą. Void natomiast mówi, że funkcja nic nie zwraca. Zauważ, że jest teraz coś takiego jak return. Teraz w main możemy napisać
  71.  
  72. int main()
  73. {
  74. int numberOne, numberTwo;
  75. cout << "podaj dwie liczby calkowite\n";
  76. cin >> numberOne >> numberTwo;
  77.  
  78. CalculatorLogic calculatorLogic;
  79. cout << "Twoj wynik to " << calculatorLogic.Add(numberOne, numberTwo) << "\n";
  80. }
  81.  
  82. możemy równie dobrze zrobić coś takiego
  83.  
  84. int main()
  85. {
  86. int numberOne, numberTwo;
  87. cout << "podaj dwie liczby calkowite\n";
  88. cin >> numberOne >> numberTwo;
  89.  
  90. CalculatorLogic calculatorLogic;
  91. int sum = calculatorLogic.Add(numberOne, numberTwo);
  92. cout << "Twoj wynik to " << sum << "\n";
  93. // tutaj mozemy dalej korzystac z tej sumy jezeli potrzebujemy
  94. }
  95.  
  96. spróbuj w funkcji Add napisać sam return bez żadnego wyrażenia i zobacz co kompilator wyświetli.
  97.  
  98. 6.3 Funkcje wywolujace inne funkcje
  99.  
  100. Funkcje mogą, a w większości to wywołują inne funkcje. Nasze funkcje powinny robić jedną rzecz. Nie było by to przyjemne kombinować z wywoływaniem funkcji tylko dlatego, że funkcja robi "za mało". Kod wtedy stał by sie nieczytelny. Na przykład jak powinno się pisać kod
  101.  
  102. void HandleInput(){}
  103.  
  104. Mówi nam, że ta funkcja obsługuje wejście (zapewne od Użytkownika). Zapewne w takiej funkcji zrobimy coś takiego
  105.  
  106. void HandleInput()
  107. {
  108. GetInput();
  109. if(!IsInputValid) // czyli jezeli input nie jest poprawny. ! jest negacja warunku. Z true robi false, z false robi true
  110. {
  111. NotifyUser()
  112. }
  113. }
  114.  
  115. Jako, że jest to bardzo ogólna funkcja, możemy tutaj posiadać funkcje które pobierają i ewentualnie komunikują się z użytkownikiem jeżeli poszło coś nie tak. Mamy pewne warstwy w tych funkcjach. Zaczynając od ogólników a kończąc na szczegółach. Pamiętaj, kod powinien być pisany tak, że osoba nietechniczna powinna być w stanie powiedzieć +- co się w nim dzieje (bez szczegółów, samymi ogólnikami)
  116.  
  117. 6.4 Referencja
  118.  
  119. Nie wyjaśnie dokładnie czym jest referencja. Temat jest dość skomplikowany i trzebaby było cytować dokumentacje języka oraz interpretacje popularnych kompilatorów. Taki rozdział powstanie, ale nie w najbliższym czasie.
  120. Co musisz wiedziec o referencji, że jest to tak jakby link do stworzonego obiektu. Coś na zasadzie jak masz strone internetową i żeby do niej się dostać to klikasz w link. Nie musisz miec fizycznie tej strony u siebie na komputerze.
  121.  
  122. Zasada od dzis: Jeżeli coś nie jest typem prostym i nie chcesz tego obiektu skopiować przekaż to przez referencje (chodzi tutaj o funkcje).
  123.  
  124. Parę przykładów
  125.  
  126. mamy taką funkcje
  127.  
  128. int Foo(int number){}
  129.  
  130. jeżeli wywołamy funkcje Foo(someRandomNumber); to tak na prawdę funkcja Foo stworzy **kopie** liczby someRandomNumber (bedą istnieć dwie zmienne o tej samej wartości). Tworzenie kopii nie jest czymś złym. Czasami chcemy stworzyć kopie. Najczęściej nie potrzebujemy tworzyć kopii, ale do typów prostych w większości nie ma sensu przekazywać referencji. Pokaże kiedy "jest" sens to robić (przeważnie można to zrobić lepiej)
  131.  
  132. class App
  133. {
  134. public:
  135. App(){}
  136. void Foo(int& number) // zauwaz ze jest & za typem danych. Jest to informacja ze number jest referencja
  137. {
  138. number = 5;
  139. }
  140. void Bar(int number) // tutaj nie ma referencji, zostanie stworzona kopia
  141. {
  142. number = 5;
  143. }
  144. };
  145.  
  146. int main()
  147. {
  148. int number = 10;
  149. App app;
  150. cout << "liczba oryginalna to " << number;
  151. app.Bar(number)
  152. cout << "liczba po wykonaniu funkcji Bar " << number;
  153. app.Foo(number);
  154. cout << "liczba po wykonaniu funkcji Foo " << number; // Liczba zostala zmieniona na liczbe 5! bo została przekazana jako "link" i funkcja pracowała na oryginale a nie na kopii!
  155. }
  156.  
  157. To jest przykład jak działa referencja. Dlaczego warto jej używać? Ze względu na prędkość wykonywania się programu. Wyobraż sobie, że masz obiekt który zajmuję w pamięci 1mb i musisz go przekazać 100 razy w funkcji. Gdy bedziesz tworzyć za każdym razem kopie to raz, ze będzie to powolne (bo program musi przekopiować wszystkie wartości) to jeszcze zajmie 100mb więcej miejsca. Gdy przekażemy referencje oba problemy znikają (referencja jest tania. **Przeważnie** zajmuję 4 bajty)
  158.  
  159. Tak więc gdy chcemy przekazać klasę to robi to w ten sposób
  160.  
  161. class App
  162. {
  163. public:
  164. App(){}
  165. void Foo(SomeClass& sc)
  166. {
  167. // tutaj operacje
  168. }
  169. };
  170.  
  171.  
  172. 6.5 Deklaracja i definicja w obrębie klasy
  173.  
  174. Jeszcze taka drobna rzecz która się przyda do robienia porządku w projekcie
  175.  
  176. Gdy mamy klase, nie musimy od razu definiować jej funkcji w środku klasy! Praktyka w C++ jest taka, ze deklaracje piszemy w plikach .h (albo hpp), a definicje w plikach .cpp
  177.  
  178. Najpierw pokaże jak rozdzielić deklaracje i definicje w obrębie jednego pliku
  179.  
  180. class Foo
  181. {
  182. public:
  183. Foo(); // zauwaz, ze jest ; i nie ma {} to jest deklaracja
  184. void Bar(); //tutaj tak samo
  185. };
  186.  
  187. Foo::Foo() // to jest definicja
  188. {
  189. }
  190.  
  191. void Foo::Bar() // to jest definicja
  192. {
  193. }
  194.  
  195. Zasada definicji jest następująca.
  196. TYPZWRACANY NAZWAKLASY::NAZWAMETODY(PARAMETRY)
  197. {
  198. }
  199.  
  200. A jak to rozdzielić na dwa pliki? Bardzo prosto. Definicje przerzuć do pliku cpp i na samym początku dołącz plik .h w którym sa deklaracje np
  201.  
  202. Foo.h
  203.  
  204. #pragma once
  205. Foo()
  206. {
  207. public:
  208. Foo();
  209. void Bar();
  210. }
  211.  
  212. Foo.cpp
  213. #include "Foo.h"
  214. Foo::Foo()
  215. {
  216. }
  217.  
  218. void Foo::Bar()
  219. {
  220. }
  221.  
  222. main.cpp
  223.  
  224. #include "Foo.h"
  225.  
  226. int main()
  227. {
  228. Foo foo;
  229. foo.Bar();
  230. }
  231.  
  232. 6.6 Zadania
  233. - Dopisz CalculatorView do projektu.
  234. - Dopisz pozostałe funkcje kalkulatora takie jak: Subtract, Multiply, Divide, Power* (chodzi o potęgowanie), SquareRoot(pierwiastkowanie), Log*, Cosinus*, Sinus* itd. Pamiętaj by korzystać z gotowych funkcji! Nie wymyślaj koła na nowo.
  235. -* Zmień kalkulator tak by przyjmował N liczb (np dopóki użytkownik nie przerwie wpisywania danych). Zastanów się nad architekturą
  236. - popraw poprzednie programy, tak by przekazywały referencje tam gdzie są potrzebne.
  237. - rodziel dotychczasowe programy tak by definicja była po za klasą
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement