Difference between revisions of "Przeciążanie metody OM SET()"
From MorphOS Library
(Translation in progress.) |
(Translation finished.) |
||
(2 intermediate revisions by the same user not shown) | |||
Line 13: | Line 13: | ||
}; | }; | ||
− | + | Najważniejszym polem struktury jest ''ops_AttrList''. Mieści ono w sobie wskaźnik do [[Taglists|taglisty]] zawierającej atrybuty i ich wartości do ustawienia w obiekcie. Pole ''ops_GInfo'' jest historyczną pozostałością i nie jest używane przez nowoczesne elementy systemu takie jak MUI, czy Reggae. Implementacja metody ''OM_SET()'' powinna przejrzeć po kolei całą taglistę i ustawić wszystkie rozpoznane atrybuty. Operacja ustawienia atrybutu może się sprowadzać do ustawienia jakiejś wartości w danych obiektu, może też uruchamiać jakieś akcje (na przykład odrysowanie obiektu). Zaleca się jednak, aby bardziej złożone akcje implementować raczej jako metody niż zmiany atrybutu. Wzorcowa metoda ''OM_SET()'' może wyglądać następująco: | |
IPTR MyClassSet(Class *cl, Object *obj, struct opSet *msg) | IPTR MyClassSet(Class *cl, Object *obj, struct opSet *msg) | ||
Line 27: | Line 27: | ||
{ | { | ||
case SOME_TAG: | case SOME_TAG: | ||
− | /* | + | /* kod zmieniający atrybut SOME_TAG */ |
tagcount++; | tagcount++; | ||
break; | break; | ||
− | /* | + | /* inne atrybuty */ |
} | } | ||
} | } | ||
Line 39: | Line 39: | ||
} | } | ||
− | + | Taglista jest iterowana za pomocą funkcji ''NextTagItem()'' z ''utility.library''. Przy każdym wywołaniu funkcja zwraca wskaźnik na kolejny element taglisty. Aktualna pozycja pamiętana jest w zmiennej ''tagptr''. Zaletą użycia tej funkcji jest automatyczna obsługa tagów specjalnych (''TAG_MORE'', ''TAG_IGNORE'', ''TAG_SKIP''), nie są one zwracane jako kolejne elementy, za to wykonywane są odpowiadające im operacje. | |
− | + | Metoda ''OM_SET()'' powinna jako wynik zwracać łączną ilość rozpoznanych i ustawionych atrybutów. Ich zliczanie odbywa się w zmiennej ''tagcounter''. Zmienna jest zwiększana o 1 przy każdym rozpoznanym tagu, a następnie powiększana o ilość atrybutów rozpoznanych w klasach nadrzędnych. | |
− | + | Typowe błędy w implementacji ''OM_SET()'' to: | |
+ | * zignorowanie zliczania rozpoznanych atrybutów, | ||
+ | * wywoływanie metody w klasie nadrzędnej w przypadku ''default'' wyrażenia ''switch''. Powoduje to wywołanie metody w klasie nadrzędniej tyle razy ile jest w tagliście atrybutów nierozpoznanych przez klasę (zamiast raz). | ||
---- | ---- | ||
− | <small> | + | <small>W rzadkich przypadkach klasa pochodna może chcieć całkowicie przejąć jakiś atrybut, tak, aby nie był wysłany do klas nadrzędnych. Można to zrobić zastępując identyfikator atrybutu w tagliście przez ''TAG_IGNORE''. Jest tu jednak pewien haczyk. Najczęściej w C i C++ taglista tworzona jest dynamicznie na stosie procesu z argumentów funkcji (np. ''SetAttrs()''). Jest jednak możliwe, że taglista będzie obiektem statycznym (na przykład globalnym, albo stworzonym w zaalokowanym bloku pamięci). W tym przypadku zmiana taga na ''TAG_IGNORE'' będzie operacją '''trwałą''', co może skutkować nieoczekiwanymi efektami. Uwaga ta dotyczy również zmiany '''wartości''' atrybutu, przed przekazaniem taglisty klasie nadrzędnej. Bezpiecznym rozwiązaniem jest sklonowanie taglisty funkcją ''CloneTagItems()'' z ''utility.library''. Następnie dokonuje się zmian w otrzymanej kopii i kopię tę przekazuje klasie nadrzędnej. Po powrocie z ''DoSuperMethodA()'' kopię zwalnia się wywołując funkcję ''FreeTagItems()''. Wadą tego rozwiązania jest możliwość wystąpienia błędu przy klonowaniu taglisty z powodu braku pamięci. Możliwość tę trzeba jakoś obsłużyć w kodzie.</small> |
Latest revision as of 08:44, 26 January 2011
Grzegorz Kraszewski
Ten artykuł w innych językach: angielski
Metoda OM_SET() jako strukturę parametrów otrzymuje strukturę opSet. Jest ona zdefiniowana w pliku nagłówkowym <intuition/classusr.h>.
struct opSet { ULONG MethodID; /* zawsze OM_SET (0x103) */ struct TagItem *ops_AttrList; struct GadgetInfo *ops_GInfo; };
Najważniejszym polem struktury jest ops_AttrList. Mieści ono w sobie wskaźnik do taglisty zawierającej atrybuty i ich wartości do ustawienia w obiekcie. Pole ops_GInfo jest historyczną pozostałością i nie jest używane przez nowoczesne elementy systemu takie jak MUI, czy Reggae. Implementacja metody OM_SET() powinna przejrzeć po kolei całą taglistę i ustawić wszystkie rozpoznane atrybuty. Operacja ustawienia atrybutu może się sprowadzać do ustawienia jakiejś wartości w danych obiektu, może też uruchamiać jakieś akcje (na przykład odrysowanie obiektu). Zaleca się jednak, aby bardziej złożone akcje implementować raczej jako metody niż zmiany atrybutu. Wzorcowa metoda OM_SET() może wyglądać następująco:
IPTR MyClassSet(Class *cl, Object *obj, struct opSet *msg) { struct TagItem *tag, *tagptr; IPTR tagcount = 0; tagptr = msg->ops_AttrList; while ((tag = NextTagItem(&tagptr)) != NULL) { switch (tag->ti_Tag) { case SOME_TAG: /* kod zmieniający atrybut SOME_TAG */ tagcount++; break; /* inne atrybuty */ } } tagcount += DoSuperMethodA(cl, obj, (Msg)msg); return tagcount; }
Taglista jest iterowana za pomocą funkcji NextTagItem() z utility.library. Przy każdym wywołaniu funkcja zwraca wskaźnik na kolejny element taglisty. Aktualna pozycja pamiętana jest w zmiennej tagptr. Zaletą użycia tej funkcji jest automatyczna obsługa tagów specjalnych (TAG_MORE, TAG_IGNORE, TAG_SKIP), nie są one zwracane jako kolejne elementy, za to wykonywane są odpowiadające im operacje.
Metoda OM_SET() powinna jako wynik zwracać łączną ilość rozpoznanych i ustawionych atrybutów. Ich zliczanie odbywa się w zmiennej tagcounter. Zmienna jest zwiększana o 1 przy każdym rozpoznanym tagu, a następnie powiększana o ilość atrybutów rozpoznanych w klasach nadrzędnych.
Typowe błędy w implementacji OM_SET() to:
- zignorowanie zliczania rozpoznanych atrybutów,
- wywoływanie metody w klasie nadrzędnej w przypadku default wyrażenia switch. Powoduje to wywołanie metody w klasie nadrzędniej tyle razy ile jest w tagliście atrybutów nierozpoznanych przez klasę (zamiast raz).
W rzadkich przypadkach klasa pochodna może chcieć całkowicie przejąć jakiś atrybut, tak, aby nie był wysłany do klas nadrzędnych. Można to zrobić zastępując identyfikator atrybutu w tagliście przez TAG_IGNORE. Jest tu jednak pewien haczyk. Najczęściej w C i C++ taglista tworzona jest dynamicznie na stosie procesu z argumentów funkcji (np. SetAttrs()). Jest jednak możliwe, że taglista będzie obiektem statycznym (na przykład globalnym, albo stworzonym w zaalokowanym bloku pamięci). W tym przypadku zmiana taga na TAG_IGNORE będzie operacją trwałą, co może skutkować nieoczekiwanymi efektami. Uwaga ta dotyczy również zmiany wartości atrybutu, przed przekazaniem taglisty klasie nadrzędnej. Bezpiecznym rozwiązaniem jest sklonowanie taglisty funkcją CloneTagItems() z utility.library. Następnie dokonuje się zmian w otrzymanej kopii i kopię tę przekazuje klasie nadrzędnej. Po powrocie z DoSuperMethodA() kopię zwalnia się wywołując funkcję FreeTagItems(). Wadą tego rozwiązania jest możliwość wystąpienia błędu przy klonowaniu taglisty z powodu braku pamięci. Możliwość tę trzeba jakoś obsłużyć w kodzie.