kategoria: C++
[#1] Wiele deklaracji funkcji o tym samym protokole
Hejka,

Czy wie ktoś może, czy jest sposób, by łatwiej deklarować w C wiele funkcji o tym samym protokole?

Typedef służy do definiowania typów i on nie nadaje się do deklarowania funkcji, co najwyżej do wskaźników do funkcji.

Pozostaje #define, ale jest to troszkę nieeleganckie.

Wie ktoś jak to zrobić?

Ostatnia aktualizacja: 15.12.2018 13:06:18 przez Hexmage960
[#2] Re: Wiele deklaracji funkcji o tym samym protokole

@Hexmage960, post #1

O tym samym czym?
[#3] Re: Wiele deklaracji funkcji o tym samym protokole

@teh_KaiN, post #2

Protokole, czyli parametrach funkcji.

Przykład:
/* Metody poszczególnych typów obiektów */
LONG Magazynier(struct Plansza *plansza, struct Obiekt *obiekt, LONG metoda, APTR dane);
LONG Skrzynia(struct Plansza *plansza, struct Obiekt *obiekt, LONG metoda, APTR dane);

Nie chcę przekopiowywać tej listy parametrów, która jest taka sama dla wszystkich tych funkcji.
[#4] Re: Wiele deklaracji funkcji o tym samym protokole

@Hexmage960, post #3

Brutalnie, acz skutecznie możesz to załatwić makrem np. tak:

#define PROTOKOL_21 struct Plansza *plansza, struct Obiekt *obiekt, LONG metoda, APTR dane

LONG Magazynier(PROTOKOL_21);

Albo nawet tak:
#define PROTOKOL_21(f) LONG f(struct Plansza *plansza, struct Obiekt *obiekt, LONG metoda, APTR dane)

PROTOKOL_21(Magazynier);

Niemniej wydaje mi się, że Twoja próba w miarę eleganckiego programowania obiektowego w C jest trochę postawiona na głowie. Ja bym zdefiniował magazyniera i skrzynię jako strkutury (niby-klasy), wskaźnik na planszę jako składową przekazywaną w konstruktorze, a metody byłyby wskaźnikami do funkcji i tu można już zastosować typedef.

Ostatnia aktualizacja: 15.12.2018 17:04:18 przez Krashan
[#5] Re: Wiele deklaracji funkcji o tym samym protokole

@Krashan, post #4

Proszę, możesz obejrzeć sobie całokształt realizacji tego kodu na GitHubie.

https://github.com/68kPoker/Magazyn

Generalnie podjąłem się takiego sposobu, jako że każdy obiekt na planszy ma mnóstwo cech wspólnych, czy to będzie skrzynia, bohater, czy kryształ. Każdy obiekt ma zatem zaimplementowane metody:
  • ANIMUJ, który wywoływany jest co jedna tura,
  • SPRAWDŹ, co sprawdza, czy obiekt można przemieścić w danym kierunku oraz
  • PRZEMIEŚĆ, który przemieszcza obiekt w danym kierunku.

Więcej metod, które będą mi potrzebne, można dopisać zupełnie transparentnie.

Generalnie wzorowałem się też na Amigowym BOOPSI, który ma bardzo zbliżony ten protokół funkcji.

Można zrealizować to na szereg innych sposobów, ale skoro ta metoda spisuje się dobrze, to myślę, że warto tak zostawić. Myślę, że jak obejrzysz całokształt kodu, to też dojdziesz do tego wniosku.

Jeśli jednak uważasz inaczej, szanuję to. Ale przypominam, że obecny kod spisuje się bardzo dobrze, więc nie odczuwam potrzeby przepisywania go.

Dzięki za podanie tych makr, rzeczywiście chyba nie istnieje jakaś metoda w samym C, by można było tak deklarować funkcje. A aż prosi się, by typedef to umożliwiał, skoro doskonale sobie radzi ze wskaźnikami do funkcji.

Myślę, że docelowo zastosuję Twoje rozwiązanie nr 1. Wiele lat temu przy pisaniu programu, który wyświetla mapy do Benefactora, miałem podobną potrzebę, gdzie miałem naprawdę dużo funkcji. I zastosowałem właśnie #define.

Dzięki. OK

Ostatnia aktualizacja: 15.12.2018 18:05:49 przez Hexmage960
[#6] Re: Wiele deklaracji funkcji o tym samym protokole

@Hexmage960, post #5

chyba nie istnieje jakaś metoda w samym C, by można było tak deklarować funkcje. A aż prosi się, by typedef to umożliwiał
Dlatego powstał C++.
[#7] Re: Wiele deklaracji funkcji o tym samym protokole

@Hexmage960, post #5

Generalnie wzorowałem się też na Amigowym BOOPSI
Nie do końca, BOOPSI ma jedną funkcję DoMethod(), którą obsługujesz wszystkie klasy obiektów, klasa obiektu jest zapisana w obiekcie. Dzięki temu problem z wielokrotnym deklarowaniem funkcji z tym samym „protokołem” nie istnieje. I można mieć dziedziczenie klas. U Ciebie to raczej niewykonalne.
[#8] Re: Wiele deklaracji funkcji o tym samym protokole

@Krashan, post #7

Każdy Dispatcher BOOPSI ma identyczny protokół - o to mi chodziło.

Co do Twojego wcześniejszego komentarza o C++, chodziło mi o to by typedefem móc deklarować funkcje na wzór definiowania wskaźnika do funkcji:

typedef LONG (*Metoda)(struct Plansza *plansza, struct Obiekt *obiekt, LONG metoda, APTR dane);

Co do dziedziczenia - tak złożone rzeczy raczej nie będą mi potrzebne w moim Sokobanie.

Zauważyłem za to jedną rzecz. Otóż metoda PRZEMIEŚĆ nie musi być implementowana indywidualnie dla każdego obiektu, jako że wykonuje (w tej chwili) dokładnie to samo.

Ostatnia aktualizacja: 15.12.2018 18:27:13 przez Hexmage960
[#9] Re: Wiele deklaracji funkcji o tym samym protokole

@Krashan, post #4

Hej,

Wpadłem na jeszcze jedno rozwiązanie. Otóż by skrócić listę argumentów mogę zastosować jedną pomocniczą funkcję, która opakuje wszystkie argumenty w strukturę. Argumentem dla wszystkich funkcji byłby wskaźnik na tę strukturę.

I tak w chwili obecnej wywołuję metody według typu obiektu, więc stosuję już opakowanie. A więc można je zastąpić tym nowym.

Generalnie nie jest to aż taka konieczność przy 3-4 obiektach, ale myślę, że przy dużej liczbie funkcji przejrzystość tych deklaracji wzrośnie ogromnie.

P.S. Z ciekawostek, to pamiętam, jak w książce o ANSI C, Kernighan i Ritchie tłumaczą zastosowanie struktur. Piszą, że zostały stworzone po prostu dla wygody.

Ogólnie wadą takiego skrótu jest to, że nie widzimy jawnie argumentów, bo są "schowane" w strukturze co czasami może zwodzić. Dlatego zastosuję je raczej dopiero wtedy, gdy typów tych obiektów zacznie znacząco przybywać.

Generalnie temat jest już opanowany.

Poniżej ilustracja:
/* Definicja struktury */
typedef struct MetodaParam
{
	struct Plansza *plansza;
	struct Obiekt *obiekt;
	LONG metoda;
	APTR dane;
} *PARAM;

/* Deklaracje */
LONG Magazynier(PARAM);
LONG Skrzynia(PARAM);
LONG Krysztal(PARAM);
LONG Stworek(PARAM);

/* Funkcja pośrednicząca */
LONG WywolajMetode(struct Plansza *plansza, struct Obiekt *obiekt, LONG metoda, APTR dane)
{
	struct MetodaParam param;
	
	param.plansza = plansza;
	param.obiekt = obiekt;
	param.metoda = metoda;
	param.dane = dane;
	return(Metody[obiekt->Typ](&param));
}


Ostatnia aktualizacja: 15.12.2018 20:50:15 przez Hexmage960
[#10] Re: Wiele deklaracji funkcji o tym samym protokole

@Hexmage960, post #3

Ja bym po prostu opakował te parametry w strukturę, byłoby to bardziej czytelne dla mnie. Cztery parametry to przynajmniej jeden za dużo, ciężko mi ogarnąć co to w zasadzie ma robić. Nawet ten komentarz na górze jakoś nie specjalnie mi pomaga w zrozumieniu. Nie wiem po co komplikować.
[#11] Re: Wiele deklaracji funkcji o tym samym protokole

@asman, post #10

Dziękuję Asman za pomoc. Wpadłem dopiero co na podobny pomysł, który przedstawiłem w poście tuż przed Tobą.

Parametry są:
- Plansza - wskaźnik na planszę,
- Obiekt - wskaźnik na obiekt, dla którego wywołujemy metodę,
- Metoda - numer metody,
- Dane - pomocnicze dane, zależne od metody.

Generalnie chodzi o przejrzystość. Plansza jest podawana odrębnie, bo nie warto powtarzać wskaźnika do niej w każdym obiekcie. Numer metody wyodrębniłem tylko dla przejrzystości i żeby go wyróżnić, choć rzeczywiście może być częścią danych.

Co do komentarza, jaki zamieściłem przed tymi deklaracjami, to rzeczywiście niewiele mówi. Dlatego polecam koledze zajrzeć na GitHuba, do którego link podałem, gdzie zamieszczony jest cały kod, by zrozumieć ogólną ideę.

Jeszcze raz dziękuję Wam za pomoc.

Ostatnia aktualizacja: 15.12.2018 21:06:09 przez Hexmage960
[#12] Re: Wiele deklaracji funkcji o tym samym protokole

@Hexmage960, post #11

Generalnie chodzi o przejrzystość



- Metoda - numer metody,
- Dane - pomocnicze dane, zależne od metody.


Chcesz przejrzystość, wywal tego typu argumenty z kodu, który nie będzie na codzień głęboko ukryty z dala od logiki samej gry. Wiem co chcesz zrobić, ale w C się takich rzeczy przejrzyście nie zrobi. Przesiądź się na C++ i przestań kombinować, bo inaczej zmienisz kod w nieczytelny zbitek znaków.

Ostatnia aktualizacja: 15.12.2018 21:48:47 przez teh_KaiN
[#13] Re: Wiele deklaracji funkcji o tym samym protokole

@teh_KaiN, post #12

Można to zrobić też na varargs jak komuś akurat tak odpowiada. Albo tak:

LONG Skrzynia(struct Plansza *plansza, struct Obiekt *obiekt, Wiadomosc wiad);

Numer metody i dane są zawarte w Wiadomości:

typedef struct 
{
	LONG metoda;
} *Wiadomosc;

Mi jednak odpowiada zastosowany sposób. BOOPSI stosuje dokładnie taki model. Nie kombinuję i uważam kod za przejrzysty.

C++ za ciężki dla mnie, przynajmniej na Amidze.

Przypominam też, że pytanie dotyczyło tylko powtarzających się argumentów funkcji. Proszę nie ingerować tak w kod. Nie widzę takiej potrzeby. Do uwag jednak się ustosunkowałem.

Ostatnia aktualizacja: 15.12.2018 22:40:29 przez Hexmage960
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem