Wpis z mikrobloga

#programowanie #cpp

Zastanawiałem się kiedyś, czy można jakoś automatycznie wyciągać typ po którym dziedziczymy w c++, coś w stylu

super
, nic na ten temat nie znalazłem ciekawego. W jakimś wątku na SO twierdzili nawet, że to niemożliwe. Potrzebuję to, żeby uniknąć błędów przy wywoływaniu metod z bazy z overridowanych metod virtualnych w aktualnej klasie.

Wczoraj kolega z pracy wymyślił taki trik, że w klasie bazowej robimy sobie typdefa (nie using, bo jesteśmy akurat ograniczeni do cpp03), którego weźmie do zdefiniowania

Inherited
w klasie dziedziczącej i potem przedefiniuje aktualny typ, itd. w kolejnych.

Pokażę od razu kod: http://ideone.com/1WOXcc

Działa na gcc, clangu i vc, ale nie jestem na 100% pewny, czy jest zgodny ze standardem.

W 7.1.2

In a given non-class scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers.


Wg mnie jest OK, bo redefiniujemy typedef z innego scope'a, mam rację?

Wołam @KrzaQ2
  • 11
@kuhar: W C++ nie ma takiego mechanizmu, bo jest wielodziedziczenie - co miałoby oznaczać jakieś "super" w takim wypadku? Z tego samego powodu, przy dziedziczeniu po kilku klasach będziesz miał niejednoznaczne definicje.

Ciekawi mnie raczej, jakich błędów chcesz się ustrzec korzystając z tego mechanizmu?
@losiul @Hauleth : Wiem, że jest wielodziedziczenie, ale w dużej liczbie projektów klasy wychodzą od jakiejś jednej bazowej i nie dziedziczy się po więcej niż 1.

Załóżmy, ze masz jakąś klasę bazową Object, po której dziedziczy cała masa innych, np. Node, Node2D, jakieś inne GuiObject, które wszystkie mają virtualną metodę onLoaded. I teraz jeżeli robimy na nią override, to chcielibysmy wewnatrz jej wywołać też metodę bardziej bazową, a następnie naszą logikę. W
@kuhar: Wydaje mi się, że robisz to źle - przynajmniej jeśli dobrze zrozumiałem. Bardzo złym pomysłem, nie tylko w C++, w każdym języku obiektowym, wywoływanie metody bazowej w przeładowanej metodzie dziedziczonej.

Zamiast tego odwróć sytuację. Klasa bazowa będzie mieć niewirutalną metodę "OnLoaded" która woła w odpowiednim momencie wirtualną metodę "protected: void doLoading()".

Generalnie przy dziedziczeniu to klasa bazowa powinna ustalać reguły, które dziedziczona ma tylko wykonać - tzn. to klasa bazowa
@kuhar: Nie wiadomo mi o takiej moƶliwości, ale zapewne z jakimś toolingiem clanga byś mógł to zrobić (ale wtedy tylko dla jednego kompilatora lub jako dodatkowy krok przed kompilacją :/ )

Ja zawsze w takich przypadkach uƶywam aliasu 'parent', ale to z reguły jest w szablonach klas, gdzie wystarczy wyciągnąć jeden z parametrów szablonu.
@losiul: W niektórych frameworkach, np. Cocosie, jest już taka architektura i nic z tym nie zrobisz.

A drugie moje zastosowanie to coś w stylu RTTI, takie obiekty z komponentami, w których możesz eksportować niektóre membery, np. do synchronizacji, zew. narzędzi itp. Coś takiego jest w Chrome engine, o ile dobrze pamiętam. W takim wypadku też musisz mieć możliwość dobrania się tylko do komponentów swoich i dokładnie 1 poziom niżej.
Nie wiadomo mi o takiej moƶliwości, ale zapewne z jakimś toolingiem clanga byś mógł to zrobić (ale wtedy tylko dla jednego kompilatora lub jako dodatkowy krok przed kompilacją :/ )


@KrzaQ2: tylko moje pytanie było zasadniczo o poprawność wrzuconego kodu...

A clang sam w sobie odpada, ze względu na specyficzny target.
@kuhar: To kicha : /. Generalnie jestem uczulony na wołanie metody bazowej z przeładowywanej - to zły design.

Wydaje mi się że taki mechanizm jest ok - jeśli działa na clang'u, gcc i vc, to w zasadzie nie ma o czym mówić ; ).

Standard C++ ma multum zakamarków, o których nie wie nawet Stroustrup - zamiast zająć się porządkowaniem języka, komisja standaryzacyjna rozpływa się w ezoteryce : >..
@kuhar: Fajny pomysł nawet, ale zdecydowanie przekombinowane :P

Jeśli masz stałą listę klas bazowych, może "przeładuj" za pomocą tag dispatchowania i isbaseof dla nich?