Rozdział 10. Funkcje zaawansowane, Informatyka, Technik informatyki, Programowanie, C++

[ Pobierz całość w formacie PDF ]
Rozdział 10.
Funkcje zaawansowane
W rozdziale 5., „Funkcje”, poznałeś podstawy pracy z funkcjami. Teraz, gdy wiesz także, jak
działają wskaźniki i referencje, możesz zgłębić zagadnienia dotyczące funkcji.
Z tego rozdziału dowiesz się, w jaki sposób:
• przeciążać funkcje składowe,
• przeciążać operatory,
• pisać funkcje, mając na celu tworzenie klas z dynamicznie alokowanymi zmiennymi.
Przeciążone funkcje składowe
Z rozdziału 5. dowiedziałeś się jak implementować polimorfizm funkcji, czyli ich przeciążanie,
przez tworzenie dwóch lub więcej funkcji o tych samych nazwach, lecz innych parametrach.
Funkcje składowe klas mogą być przeciążane w dokładnie ten sam sposób.
Klasa
Rectangle
(prostokąt), zademonstrowana na listingu 10.1, posiada dwie funkcje
DrawShape()
(rysuj kształt). Pierwsza z nich, nie posiadająca parametrów, rysuje prostokąt na
podstawie bieżących wartości składowych danego egzemplarza klasy. Druga funkcja otrzymuje
dwie wartości (szerokość i długość) i rysuje na ich podstawie prostokąt, ignorując bieżące wartości
zmiennych składowych.
Listing 10.1. Przeciążone funkcje składowe
0: //Listing 10.1 Przeciążanie funkcji składowych klasy
1:
2: #include <iostream>
3:
4: // Deklaracja klasy Rectangle
5: class Rectangle
6: {
7: public:
8: // konstruktory
9: Rectangle(int width, int height);
10: ~Rectangle(){}
11:
12: // przeciążona funkcja składowa klasy
13: void DrawShape() const;
14: void DrawShape(int aWidth, int aHeight) const;
15:
16: private:
17: int itsWidth;
18: int itsHeight;
19: };
20:
21: // implementacja konstruktora
22: Rectangle::Rectangle(int width, int height)
23: {
24: itsWidth = width;
25: itsHeight = height;
26: }
27:
28:
29: // Przeciążona funkcja DrawShape - nie ma parametrów
30: // Rysuje kształt w oparciu o bieżące wartości zmiennych
składowych
31: void Rectangle::DrawShape() const
32: {
33: DrawShape( itsWidth, itsHeight);
34: }
35:
36:
37: // Przeciążona funkcja DrawShape - z dwoma parametrami
38: // Rysuje kształt w oparciu o podane wartości
39: void Rectangle::DrawShape(int width, int height) const
40: {
41: for (int i = 0; i<height; i++)
42: {
43: for (int j = 0; j< width; j++)
44: {
45: std::cout << "*";
46: }
47: std::cout << "\n";
48: }
49: }
50:
51: // Główna funkcja demonstrująca przeciążone funkcje
52: int main()
53: {
54: // inicjalizujemy prostokąt 30 na 5
55: Rectangle theRect(30,5);
56: std::cout << "DrawShape(): \n";
57: theRect.DrawShape();
58: std::cout << "\nDrawShape(40,2): \n";
59: theRect.DrawShape(40,2);
60: return 0;
61: }
Wynik
DrawShape():
******************************
******************************
******************************
******************************
******************************
DrawShape(40,2):
****************************************
****************************************
Analiza
Listing 10.1 prezentuje okrojoną wersję programu, zamieszczonego w podsumowaniu wiadomości
po rozdziale 7. Aby zaoszczędzić miejsce, z programu usunięto sprawdzanie niepoprawnych
wartości, a także niektóre z akcesorów. Główny program został sprowadzony do dużo prostszej
postaci, w której nie ma już menu.
Najważniejszy kod znajduje się w liniach 13. i 14., gdzie przeciążona została funkcja
DrawShape()
. Implementacja tych przeciążonych funkcji składowych znajduje się w liniach od
29. do 49. Zwróć uwagę, że funkcja w wersji bez parametrów po prostu wywołuje funkcję z
parametrami, przekazując jej bieżące zmienne składowe. Postaraj się nigdy nie powtarzać tego
samego kodu w dwóch funkcjach, może to spowodować wiele problemów z zachowaniem ich w
zgodności w trakcie wprowadzaniu poprawek (może stać się to przyczyną błędów).
Główna funkcja tworzy w liniach od 51. do 61. obiekt prostokąta, po czym wywołuje funkcję
DrawShape()
, najpierw bez parametrów, a potem z dwoma parametrami typu
int
.
Kompilator na podstawie ilości i typu podanych parametrów wybiera metodę. Można sobie
wyobrazić także trzecią przeciążoną funkcję o nazwie
DrawShape()
, która otrzymywałaby jeden
wymiar oraz wartość wyliczeniową, określającą, czy jest on wysokością czy szerokością (wybór
należałby do użytkownika).
Użycie wartości domyślnych
Podobnie, jak w przypadku funkcji składowych klasy, funkcje globalne również mogą mieć jedną
lub więcej wartości domyślnych. W przypadku deklaracji wartości domyślnych w funkcjach
składowych stosujemy takie same reguły, jak w funkcjach globalnych, co ilustruje listing 10.2.
Listing 10.2. Użycie wartości domyślnych
0: //Listing 10.2 Domyślne wartości w funkcjach składowych
1:
2: #include <iostream>
3:
4: using namespace std;
5:
6: // Deklaracja klasy Rectangle
7: class Rectangle
8: {
9: public:
10: // konstruktory
11: Rectangle(int width, int height);
12: ~Rectangle(){}
13: void DrawShape(int aWidth, int aHeight,
14: bool UseCurrentVals = false) const;
15:
16: private:
17: int itsWidth;
18: int itsHeight;
19: };
20:
21: // implementacja konstruktora
22: Rectangle::Rectangle(int width, int height):
23: itsWidth(width), // inicjalizacje
24: itsHeight(height)
25: {} // puste ciało konstruktora
26:
27:
28: // dla trzeciego parametru jest używana domyślna wartość
29: void Rectangle::DrawShape(
30: int width,
31: int height,
32: bool UseCurrentValue
33: ) const
34: {
35: int printWidth;
36: int printHeight;
37:
38: if (UseCurrentValue == true)
39: {
40: printWidth = itsWidth; // używa bieżących wartości
klasy
41: printHeight = itsHeight;
42: }
43: else
44: {
45: printWidth = width; // używa wartości z
parametrów
46: printHeight = height;
47: }
48:
49:
50: for (int i = 0; i<printHeight; i++)
51: {
52: for (int j = 0; j< printWidth; j++)
53: {
54: cout << "*";
55: }
56: cout << "\n";
57: }
58: }
59:
60: // Główna funkcja demonstrująca przeciążone funkcje
61: int main()
62: {
63: // inicjalizujemy prostokąt 30 na 5
64: Rectangle theRect(30,5);
65: cout << "DrawShape(0,0,true)...\n";
66: theRect.DrawShape(0,0,true);
67: cout <<"DrawShape(40,2)...\n";
68: theRect.DrawShape(40,2);
69: return 0;
70: }
Wynik
DrawShape(0,0,true)...
******************************
******************************
******************************
******************************
******************************
DrawShape(40,2)...
****************************************
****************************************
Analiza
Listing 10.2 zastępuje przeciążone funkcje
DrawShape()
pojedynczą funkcją z domyślnym
parametrem. Ta funkcja, zadeklarowana w linii 13., posiada trzy parametry. Dwa pierwsze,
aWidth
(szerokość) i
aHeight
(wysokość) są typu
int
, zaś trzeci,
UseCurrentVals
(użyj
bieżących wartości), jest zmienną typu
bool
o domyślnej wartości
false
.
Implementacja tej nieco udziwnionej funkcji rozpoczyna się w linii 28. Sprawdzany jest w niej
trzeci parametr,
UseCurrentValue
. Jeśli ma on wartość
true
, wtedy do ustawienia lokalnych
zmiennych
printWidth
(wypisywana szerokość) i
printHeight
(wypisywana wysokość) są
używane zmienne składowe klasy,
itsWidth
oraz
itsHeight
.
Jeśli parametr
UseCurrentValue
ma wartość
false
, podaną przez użytkownika, lub ustawioną
domyślnie, wtedy zmiennym
printWidth
i
printHeight
są przypisywane wartości dwóch
pierwszych argumentów funkcji.
Zwróć uwagę, że gdy parametr
UseCurrentValue
ma wartość
true
, wartości dwóch pierwszych
parametrów są całkowicie ignorowane.
Wybór pomiędzy wartościami domyślnymi a
przeciążaniem funkcji
Listingi 10.1 i 10.2 dają ten sam wynik, lecz przeciążone funkcje z listingu 10.1 są łatwiejsze do
zrozumienia i wygodniejsze w użyciu. Poza tym, gdy jest potrzebna trzecia wersja — na przykład,
gdy użytkownik chce dostarczyć szerokości albo wysokości osobno — można łatwo stworzyć
kolejną przeciążoną funkcję. Z drugiej strony, w miarę dodawania kolejnych wersji, wartości
domyślne mogą szybko stać się zbyt skomplikowane.
W jaki sposób podjąć decyzję, czy użyć przeciążania funkcji, czy wartości domyślnych? Oto
ogólna reguła:
Przeciążania funkcji używaj, gdy:
• nie istnieje sensowna wartość domyślna,
• używasz różnych algorytmów,
• chcesz korzystać z różnych rodzajów parametrów funkcji.
[ Pobierz całość w formacie PDF ]

  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • frania1320.xlx.pl
  • Tematy