W C++ Builderze można dla właściwości klasy zdefiniować metody dostępowe, tzn. funkcje służące do zapisu i odczytu zmiennej:
int GetValue() { ... }
void SetValue(int) { ... }
__property int Value = { read = GetValue, write=SetValue };
W Microsoft Visual Studio też coś takiego jest, tylko składnia jest troszkę inna. Standard ISO C++ czegoś takiego nie przewiduje. Przeglądałem dokumentację GCC, ale też czegoś takiego nie widziałem w rozszerzeniach.
Czy może jednak jest coś takiego? A może jest jakaś biblioteka wprowadzająca taki mechanizm metodą kombinowaną?
Dopisane:
tytuł zmieniłem, bo może enigmatyczny był :] ale nie o tym chciałem:
Zrobiłem rozwiązanie kombinowane, które ma jednak dużą wadę - na każdą właściwość klasy powstaje narzut 4 bajtów. Postaram się wyjaśnić, jak to wymodziłem - może ktoś będzie widział, co trzeba w tym rozumowaniu zmienić, żeby pozbyć się tego narzutu...
Aby zmienna reagowała na zapis / odczyt opakowałem ją w klasę i przeładowałem operator konwersji i przypisania. Później się zastanowię nad szczegółami przeładowania odpowiednio reszty potrzebnych:
class Opakowanie {
private:
int value;
public:
int operator=(int v) { cout << "set"; return value=v; }
operator int() { cout << "get"; return value; }
};
Ale ja chcę, żeby klasa wywoływała zewnętrzne funkcje dostępowe. sama zmienna value też lepiej, żeby była na zewnątrz. Tzn. mam komponent właściwy i w nim wszystko się znajduje. Posiada on opakowaną właściwość. I ma ona korzystać nie ze swoich jakichś funkcji, ale właśnie z metod i zmiennych komponentu.
wymyśliłem coś takiego:
istnieje wskaźnik do składowej obiektu. Można nim inicjalizować szablon - a więc już w trakcie deklaracji mogę określić funkcje dostępowe. Rozrasta mi się sekcja kodu, ale to jeszcze nie powoduje narzutu na każdy obiekt danej klasy.
Szablon działa na zasadzie Opakowania powyżej, tzn ma operatory konwersji i przypisania. Wewnątrz nich wywołuje odpowiednie metody używając otrzymanych wskaźników. I tu mam problem: wskaźnik do składowej może być użyty tylko w połączeniu z obiektem/jego adresem.
Wskutek tego każdy szablon zawiera wskaźnik owner, którego używa się do wywołania metod dostępowych. Wskaźnik ten jest inicjalizowany podczas konstrukcji wskaźnikiem this komponentu.
class TJakisKomponent {
protected:
// "surowa" wartość i metody dostępowe
int value;
void setValue(int v) { cout << "set"; value=v; }
int getValue() { cout << "get"; return value; }
public:
// wskaźniki do metod dostępowych
typedef void (TJakisKomponent ::*pset)(int);
typedef int (TJakisKomponent ::*pget)();
// klasa szablonowa pobierająca adresy metod dostępowych
// nie uzależniam od typu właściwości na razie, żeby nie zaciemniać do końca
template<pset set, pget, get> class TAccessor {
private:
// to jest narzut - właściwość musi znać adres obiektu, a do this "TJakisKomponent " nie dojdzie
TJakisKomponent * owner;
public:
// podczas konstrukcji trzeba inicjalizować właściwość
TAccessor(TJakisObiekt* o) : owner(o) {}
//użycie wskaźnika do funkcji skł. klasy (tu jest właśnie potrzebny adres obiektu, bez niego wskaźnik jest bezużyteczny)
void operator=(int value) { (owner ->* set)(value); }
// j.w.
void operator int() { return (owner ->* get)(); }
};
// przyjaźń, żeby mógł używać metod chronionych dostępowych:
template<class,class> friend class TAccessor;
// po tej walce można wreszcie dać właściwości :)
TAccessor < &TJakisObiekt::setValue, &TJakisObiekt::getValue > Value;
};
po wykombinowaniu kilku makr i pewnych modyfikacjach ma to nawet znośną składnię, więc gdyby nie ten narzut, to byłbym zadowolony (sekcja kodu to mi może rosnąć w nieskończoność :] ):
class TArea {
private:
int value;
string name;
protected:
virtual int getValue();
virtual void setValue(int w);
virtual string getName();
virtual void setName(const string& n);
public:
#define useAccessors TArea
__use_accessor(int);
__use_fast_accessor(string);
__accessor (int, Value);
__accessor (string, Name);
};
Wskutek całego tego wywodu aktualizuje się trochę lista pytań:
- czy GCC ma jakąś normalniejszą możliwość obsługi właściwości
- czy może jest jakaś biblioteka, która to robi normalniej
- czy może da się to jakoś zmodyfikować, żeby normalniej