Ponieważ w C++ nie ma mechanizmu właściwości, do kontroli dostępu do pól w klasie wykorzystuje się metody dostępowe, czyli akcesory. Od kiedy zajmuję się programowaniem w tym języku, starałem się wynaleźć jakąś sensowną konwencję odnośnie tego, w jakiej postaci metody te zapisywać i jak je nazywać.
Niektórzy preferują na przykład utworzenie tylko jednej funkcji postaci:
która ustawia nową wartość pola i jednocześnie zwraca nam poprzednią. Takie rozwiązania realizuje chociażby funkcja set_new_handler
, ustawiająca procedurę obsługi błędu braku pamięci dla operatora new
. Nie akceptuję tego sposobu z jednego prostego powodu: bardzo częsta operacja pobrania wartości wymaga tutaj aż dwóch wywołań, które wyglądają co najmniej dziwnie.
Akcesory muszą więc być dwa (get/set). Pozostaje wtedy kwestia: jak je nazywać? Tutaj doszedłem do trzech możliwości:
X
. Dla kompilatora będą one z łatwością odróżnialne, jako że getter jest bezparametrowy, a setter oczywiście nie.GetX
i SetX
.SetX
, ale getter po prostu X
.Chyba każdy z tych trzech sposobów widziałem w użyciu w jakiejś popularnej bibliotece, więc nie są to tylko teoretyczne propozycje. Sam zresztą wypróbowałem po kolei każdą z nich.
I tak rozwiązanie pierwsze jest na pewno najkrótsze, ale sprawia, że wywołania setterów wyglądają dziwnie. Widząc:
można zastanawiać się, co autor miał na myśli, a interpretacja “ustaw obiekt kamery dla sceny” nie musi być wcale tą, która nasuwa się jako pierwsza.
Z kolei drugi sposób (z Get
/Set
) jest całkowicie jednoznaczny, lecz w zamian potrafi wyprodukować łańcuszki w rodzaju poniższego:
Wszystkie te Get
y trudno uznać za potrzebne do szczęścia, chociaż javowcy pewnie by się kłócili ;)
Dlatego też sposób trzeci polega na pozbyciu się ich (Get
ów, nie koderów Javy :>). Tę właśnie konwencję (SetX
/X
) wykorzystuję obecnie i jak dotąd stwierdzam, że sprawdza się dobrze. Dla ostatecznych wniosków byłby jednak potrzebny dłuższy okres, by przekonać się, czy po upływie pewnego czasu nadal mogę patrzeć na swój kod z zachowaniem równowagi psychicznej ;]
Mysle, ze wybrales srednio dobra droge :) Get/Set jest jak najbardziej poprawne i doskonale ulatwia czytanie kodu. Co do nazewnictwa funkcji i ogolnie porzadku w kodzie polecam lekture “Clean Code” Roberta C. Martina.
Swego czasu próbowałem zasymulować akcesory makrami, wyglądało to tak:
#define Accesor template struct
#define set void operator=(const T& value)
#define get operator T() const
//…
int param_x;
Accesor ToParamX
{
set
{
cout << “Accesor set” << endl;
param_x = value;
}
get
{
cout << “Accesor get” << endl;
return param_x;
}
};
ToParamX ParamX;
[/cpp]
Ale nie pamiętam jak się to skończyło, czy nie działało(najprawdopodobniej), czy po prostu zdecydowałem że to mi zasyfi kod za bardzo, w każdym razie teraz używam rozwiązania 1.
Tak, jak teraz przejrzałem ten kod to okazuje się że to jednak nie działało… ale szperając po dysku znalazłem plik z rozwiązaniem działającym: Link. Ale jak widać jest to zbyt śmieciaste rozwiązanie, więc można to traktować tylko jako ciekawostkę, czy proof of concept że accesory(właściwości) w c++ są możliwe jak się człowiek uprze ^^
polymorph: Na coś podobnego (do tego rozwiązania z linku) wpadłem już jakiś czas temu, ale nie pomyślałem o użyciu boost::bind przez co rzecz nie była nawet teoretycznie używalna (wymagałaby drugiego parametru w szablonie: typu klasy, w której zawarty jest akcesor).
To, co pokazałeś, jest zdecydowanie lepsze – właściwie to już jest niemal to samo, co properties z Delphi (po niezbyt trudno uzupełnieniu o drugi szablon, ReadOnlyAccessor).
Jest jeszcze notacja put_X i get_X, stosowana w klasach COM AFAIR.
Ja stosuję nazwy GetX i SetX. Jest taka zasada, która mówi, że nazwy metod powinny mieć czasownik jako że są to operacje, tak jak nazwy pól rzeczownik.