[ Pobierz całość w formacie PDF ]
potrzeby funkcji kopiowane są więc tylko 4 bajty odwołania, a nie czasem wiele
kilobajtów właściwego obiektu!
Przy tej samej okazji narzekaliśmy jednak, że zastosowanie wskazników wymaga
przeformatowania składni całego kodu, w którym należy dodać konieczne dereferencje i
zmienić operatory wyłuskania. To niewielki, ale jednak dolegliwy kłopot.
I oto nagle pojawia się cudowne rozwiązanie :) Referencje, bo o nich rzecz jasna
mówimy, są także odwołaniami do obiektów, ale możliwe jest stosowanie wobec nich
zwyczajnej składni, bez uciążliwości związanych ze wskaznikami. Czyniąc je parametrami
funkcji, powinniśmy więc upiec dwie pieczenie na jednym ogniu, poprawiając zarówno
osiągi programu, jak i własne samopoczucie :D
Spójrzmy zatem jeszcze raz na funkcję Wyszukaj(), z którą spotkaliśmy się już przy
wskaznikach. Tym razem jej parametry będą jednak referencjami. Oto jak wpłynie to na
wygląd kodu:
#include
int Wyszukaj (const std::string& strSzukany,
const std::string& strPrzeszukiwany)
{
// przeszukujemy nasz napis
for (unsigned i = 0;
i
{
Podstawy programowania
310
// porównujemy kolejne wycinki napisu
if (strPrzeszukiwany.substr(i, strSzukany.length())
== strSzukany)
// jeżeli wycinek zgadza się, to zwracamy jego indeks
return i;
}
// w razie niepowodzenia zwracamy -1
return -1;
}
Obecnie nie widać tu najmniejszych oznak silenia się na jakąkolwiek optymalizację, a
mimo jest ona taka sama jak w wersji wskaznikowej. Powodem jest forma nagłówka
funkcji:
int Wyszukaj (const std::string& strSzukany,
const std::string& strPrzeszukiwany)
Oba jej parametry są tutaj referencjami do stałych napisów, a więc nie są kopiowane
w inne miejsca pamięci wyłącznie na potrzeby funkcji. A jednak, chociaż faktycznie
funkcja otrzymuje tylko ich adresy, możemy operować na tych parametrach zupełnie tak
samo, jakbyśmy dostali całe obiekty poprzez ich wartości. Mamy więc zarówno wygodną
składnię, jak i dobrą wydajność tak napisanej funkcji.
Zatrzymajmy się jeszcze przez chwilę przy modyfikatorach const w obu parametrach
funkcji. Obydwa napisy nie w jej ciele w żaden sposób zmieniane (bo i nie powinny),
zatem logiczne jest zadeklarowanie ich jako referencji do stałych. W praktyce tylko takie
referencje stosuje się jako parametry funkcji; jeżeli bowiem należy zwrócić jakąś wartość
poprzez parametr, wtedy lepiej dla zaznaczenia tego faktu użyć odpowiedniego
wskaznika.
Zwracanie referencji
Na podobnej zasadzie, na jakiej funkcje mogą pobierać referencje poprzez swoje
parametry, mogą też je zwracać na zewnątrz. Uzasadnienie dla tego zjawiska jest
również takie samo, czyli zaoszczędzenie niepotrzebnego kopiowania wartości.
Najprotszym przykładem może być ciekawe rozwiązanie problemu metod dostępowych -
tak jak poniżej:
class CFoo
{
private:
unsigned m_uPole;
public:
unsigned& Pole() { return m_uPole; }
};
Ponieważ metoda Pole() zwraca referencję, możemy używać jej niemal tak samo, jak
zwyczajnej zmiennej:
CFoo Foo;
Foo.Pole() = 10;
std::cout
Oczywiście kwestia, czy takie rozwiązanie jest w danym przypadku pożądane, jest mocno
indywidualna. Zawsze należy rozważyć, czy nie lepiej zastosować tradycyjnego wariantu
metod dostępowych - szczególnie, jeżeli chcemy zachowywać kontrolę nad wartościami
przypisywanymi polom.
Wskazniki 311
Z praktycznego punktu widzenia zwracanie referencji nie jest więc zbytnio przydatną
możliwością. Wspominam jednak o niej, gdyż stanie się ona niezbędna przy okazji
przeładowywania operatorów - zagadnienia, którym zajmiemy się w jednym z przyszłych
rozdziałów.
***
Tym drobnym wybiegnięciem w przyszłość zakończymy nasze spotkania ze wskaznikami
na zmienne. Jeżeli miałeś jakiekolwiek wątpliwości co do użyteczności tego elementu
języka C++, to chyba do tego momentu zostały one całkiem rozwiane. Najlepiej jednak
przekonasz się o przydatności mechanizmów wskazników i referencji, kiedy sam będziesz
miał okazję korzystać z nich w swoich własnych aplikacjach. Przypuszczam także, że owe
okazje nie będą wcale odosobnionymi przypadkami, ale stałą praktyką programistyczną.
Oprócz wskazników na zmienne język C++ oferuje również inną ciekawą konstrukcję,
jaką są wskazniki na funkcje. Nie od rzeczy będzie więc zapoznanie się z nimi, co też
pilnie uczynimy.
Wskazniki do funkcji
Myśląc o tym, co jest przechowywane w pamięci operacyjnej, zwykle wyobrażamy sobie
różne dane programu: zmienne, tablice, struktury itp. One stanowią informacje
reprezentowane w komórkach pamięci, na których aplikacja wykonuje swoje działania.
[ Pobierz całość w formacie PDF ]