Jaka jest preferowana metoda uzyskania odpowiednika języka Java w języku C ++ instanceof
?
java
c++
oop
instanceof
Yuval Adam
źródło
źródło
Odpowiedzi:
Spróbuj użyć:
Wymaga to włączenia w kompilatorze obsługi rtti.
EDYCJA: Mam kilka dobrych komentarzy na temat tej odpowiedzi!
Za każdym razem, gdy potrzebujesz użyć dynamicznej transmisji (lub instanceof), lepiej zadaj sobie pytanie, czy jest to konieczne. Zazwyczaj jest to oznaka złego projektu.
Typowe obejścia tego problemu polegają na umieszczeniu specjalnego zachowania dla klasy, którą sprawdzasz, w funkcji wirtualnej w klasie bazowej lub być może wprowadzeniu czegoś takiego jak gość, w którym możesz wprowadzić określone zachowanie dla podklas bez zmiany interfejsu (z wyjątkiem dodania interfejsu akceptacji przez kierunek).
Jak wskazano, dynamic_cast nie jest darmowy. Prostym i konsekwentnie działającym hackem, który obsługuje większość (ale nie wszystkie przypadki), jest w zasadzie dodanie wyliczenia reprezentującego wszystkie możliwe typy, jakie może mieć Twoja klasa i sprawdzenie, czy masz właściwy.
To nie jest dobry projekt z oo, ale może być obejściem, a jego koszt to mniej więcej wirtualne wywołanie funkcji. Działa również niezależnie od tego, czy RTTI jest włączony czy nie.
Pamiętaj, że to podejście nie obsługuje wielu poziomów dziedziczenia, więc jeśli nie będziesz ostrożny, możesz skończyć z kodem wyglądającym tak:
źródło
W zależności od tego, co chcesz zrobić, możesz to zrobić:
Posługiwać się:
Działa to jednak wyłącznie na typach znanych kompilatorowi.
Edytować:
Ten kod powinien działać dla wskaźników polimorficznych:
Przykład: http://cpp.sh/6qir
źródło
Instancja implementacji bez Dynamic_cast
Myślę, że to pytanie jest nadal aktualne. Korzystając ze standardu C ++ 11, możesz teraz zaimplementować
instanceof
funkcję bez użyciadynamic_cast
takiego:Ale nadal jesteś zależny od
RTTI
wsparcia. Oto moje rozwiązanie tego problemu w zależności od niektórych makr i magii metaprogramowania. Jedyną wadą jest to, że takie podejście nie działa w przypadku wielokrotnego dziedziczenia .InstanceOfMacros.h
Próbny
Możesz następnie użyć tych rzeczy ( ostrożnie ) w następujący sposób:
DemoClassHierarchy.hpp *
Poniższy kod przedstawia małe demo w celu zweryfikowania szczątkowego prawidłowego zachowania.
InstanceOfDemo.cpp
Wynik:
Występ
Najciekawsze pytanie, jakie się teraz pojawia, brzmi: czy te złe rzeczy są bardziej wydajne niż ich użycie
dynamic_cast
. Dlatego napisałem bardzo podstawową aplikację do pomiaru wydajności.InstanceOfPerformance.cpp
Wyniki różnią się i są zasadniczo oparte na stopniu optymalizacji kompilatora. Kompilowanie programu pomiaru wydajności przy użyciu
g++ -std=c++11 -O0 -o instanceof-performance InstanceOfPerformance.cpp
danych wyjściowych na moim komputerze lokalnym było:Mhm, ten wynik był bardzo otrzeźwiający, ponieważ czasy pokazują, że nowe podejście nie jest dużo szybsze w porównaniu do
dynamic_cast
podejścia. Jest nawet mniej wydajny dla specjalnego przypadku testowego, który sprawdza, czy wskaźnikA
jest instancjąA
. ALE fala się zmienia, dostrajając nasz plik binarny za pomocą optymalizacji kompilatora. Odpowiednie polecenie kompilatora tog++ -std=c++11 -O3 -o instanceof-performance InstanceOfPerformance.cpp
. Wynik na mojej lokalnej maszynie był niesamowity:Jeśli nie jesteś zależny od wielokrotnego dziedziczenia, nie jesteś przeciwnikiem starych dobrych makr C, RTTI i metaprogramowania szablonów i nie jesteś zbyt leniwy, aby dodać kilka małych instrukcji do klas hierarchii klas, to takie podejście może nieco poprawić twoją aplikację jeśli chodzi o jego wydajność, jeśli często kończy się na sprawdzeniu wystąpienia wskaźnika. Ale używaj go ostrożnie . Nie ma gwarancji na poprawność tego podejścia.
Uwaga: Wszystkie demonstracje zostały skompilowane przy użyciu
clang (Apple LLVM version 9.0.0 (clang-900.0.39.2))
MacOS Sierra na MacBooku Pro w połowie 2012 roku.Edycja: Testowałem również wydajność na komputerze z systemem Linux przy użyciu
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
. Na tej platformie korzyść związana z wydajnością nie była tak znacząca, jak w przypadku MacO z clang.Dane wyjściowe (bez optymalizacji kompilatora):
Dane wyjściowe (z optymalizacją kompilatora):
źródło
dynamic_cast
wiadomo, że jest nieefektywny. Przechodzi przez hierarchię dziedziczenia i jest to jedyne rozwiązanie, jeśli masz wiele poziomów dziedziczenia i musisz sprawdzić, czy obiekt jest instancją dowolnego z typów w swojej hierarchii typów.Ale jeśli bardziej ograniczona forma
instanceof
tego sprawdza tylko, czy obiekt jest dokładnie taki, jaki określisz, wystarczy dla twoich potrzeb, funkcja poniżej byłaby o wiele bardziej wydajna:Oto przykład wywołania powyższej funkcji:
Podaj typ szablonu
A
(jako typ, którego szukasz) i przekaż obiekt, który chcesz przetestować, jako argument (z którego typu szablonuK
byłby wywnioskowany).źródło
źródło
instanceof
odpytuje typ dynamiczny, ale w tej odpowiedzi typ dynamiczny i statyczny zawsze odpowiadają.Działa to idealnie dla mnie przy użyciu Code :: Blocks IDE z kompilatorem GCC
źródło
typeid
”, co wprawdzie jest błędne („Nie ma gwarancji, że do tej samej instancji std :: type_info przywołane zostaną wszystkie oceny wyrażenia typeid tego samego typu ...assert(typeid(A) == typeid(A)); /* not guaranteed */
”, patrz cppreference.com ), wskazuje, że przynajmniej próbował odpowiedzieć na pytanie, choć bezskutecznie, ponieważ zaniedbał zaoferowania minimalnego działającego przykładu.