Słyszałem, że szablony funkcji członka klasy C ++ nie mogą być wirtualne. Czy to prawda?
Jeśli mogą być wirtualne, jaki jest przykład scenariusza, w którym można by użyć takiej funkcji?
c++
templates
virtual-functions
function-templates
c++-faq
WannaBeGeek
źródło
źródło
Odpowiedzi:
Szablony dotyczą generowania kodu kompilatora w czasie kompilacji . Funkcje wirtualne polegają na tym, aby system wykonawczy zastanawiał się, którą funkcję wywołać w czasie wykonywania .
Gdy system wykonawczy zorientuje się, że będzie musiał wywołać funkcję wirtualną opartą na szablonie, kompilacja jest zakończona, a kompilator nie może już wygenerować odpowiedniej instancji. Dlatego nie możesz mieć szablonów funkcji wirtualnego członka.
Istnieje jednak kilka potężnych i interesujących technik wynikających z łączenia polimorfizmu i szablonów, w szczególności tak zwane wymazywanie typu .
źródło
Virtual functions are all about the run-time system figuring out which function to call at run-time
- przepraszam, ale jest to raczej zły sposób i dość mylący. Jest to tylko pośrednia i nie ma w tym przypadku żadnego „środowiska uruchomieniowego”, w czasie kompilacji wiadomo, że wywoływana funkcja jest wskazywana przez n-ty wskaźnik w tabeli. „Zrozumienie” oznacza, że istnieją kontrole typu i tak nie jest.Once the run-time system figured out it would need to call a templatized virtual function
- w czasie kompilacji wiadomo, czy funkcja jest wirtualna.void f(concr_base& cb, virt_base& vb) { cb.f(); vb.f(); }
, to „wie”, która funkcja jest wywoływana w punkciecb.f()
wywoływanym, i nie wie o tymvb.f()
. Ta ostatnia musi znaleźć się w czasie pracy , w systemie czasu . To, czy chcesz nazwać to „rozgryzaniem” i czy jest to mniej lub bardziej wydajne, nie zmienia tych faktów.Z szablonów C ++ Kompletny przewodnik:
źródło
C ++ nie zezwala obecnie na funkcje wirtualnych elementów szablonu. Najbardziej prawdopodobną przyczyną jest złożoność jego wdrożenia. Rajendra podaje dobry powód, dla którego nie można tego zrobić teraz, ale byłoby to możliwe przy rozsądnych zmianach standardu. Zwłaszcza ustalenie, ile instancji funkcji szablonowej faktycznie istnieje, a zbudowanie tabeli vt wydaje się trudne, jeśli weźmie się pod uwagę miejsce wirtualnego wywołania funkcji. Standardy ludzie mają teraz wiele innych rzeczy do zrobienia, a C ++ 1x to także dużo pracy dla autorów kompilatorów.
Kiedy potrzebujesz szablonowej funkcji członka? Kiedyś natknąłem się na taką sytuację, w której próbowałem refaktoryzować hierarchię za pomocą czystej wirtualnej klasy bazowej. Był to zły styl wdrażania różnych strategii. Chciałem zmienić argument jednej z funkcji wirtualnych na typ liczbowy i zamiast przeciążać funkcję członka i zastępować każde przeciążenie we wszystkich podklasach, próbowałem użyć funkcji wirtualnych szablonów (i musiałem się dowiedzieć, że one nie istnieją .)
źródło
Tabele funkcji wirtualnych
Zacznijmy od pewnego tła na temat tabel funkcji wirtualnych i ich działania ( źródło ):
Mój problem lub jak tu przybyłem
Próbuję teraz użyć czegoś takiego dla klasy bazowej pliku kostek z zoptymalizowanymi funkcjami ładowania zoptymalizowanymi w szablonie, które będą wdrażane inaczej dla różnych typów kostek (niektóre przechowywane w pikselach, inne w obrazach itp.).
Jakiś kod:
To, co chciałbym, żeby było, ale nie będzie się kompilowało z powodu wirtualnego zestawu szablonów:
Skończyłem przenoszenie deklaracji szablonu na poziom klasy. To rozwiązanie zmusiłoby programy do znajomości określonych rodzajów danych, które czytałyby przed ich odczytaniem, co jest niedopuszczalne.Rozwiązanie
Uwaga, to nie jest bardzo ładne, ale pozwoliło mi to usunąć powtarzający się kod wykonawczy
1) w klasie bazowej
2) oraz w klasach dziecięcych
Zauważ, że LoadAnyCube nie jest zadeklarowany w klasie podstawowej.
Oto kolejna odpowiedź na przepełnienie stosu z obejściem: potrzebujesz obejścia elementu wirtualnego szablonu .
źródło
Poniższy kod można skompilować i działa poprawnie, używając MinGW G ++ 3.4.5 w Windows 7:
a wynikiem jest:
A później dodałem nową klasę X:
Kiedy próbowałem użyć klasy X w main () w następujący sposób:
g ++ zgłoś następujący błąd:
Jest więc oczywiste, że:
źródło
Nie, nie mogą. Ale:
ma taki sam efekt, jeśli wszystko, co chcesz zrobić, to mieć wspólny interfejs i odroczyć implementację do podklas.
źródło
Foo
wskaźnik jest kwalifikowany jakoFoo<Bar>
, nie może wskazywać naFoo<Barf>
lubFoo<XXX>
.Nie, funkcje elementów szablonu nie mogą być wirtualne.
źródło
W pozostałych odpowiedziach proponowana funkcja szablonu jest fasadą i nie oferuje żadnych praktycznych korzyści.
Język nie pozwala na korzystanie z funkcji wirtualnych szablonów, ale dzięki obejściu można mieć oba, np. Jedną implementację szablonu dla każdej klasy i wspólny wirtualny interfejs.
Konieczne jest jednak zdefiniowanie dla każdej kombinacji typów szablonów funkcji wirtualnego opakowania wirtualnego:
Wynik:
Wypróbuj tutaj
źródło
Aby odpowiedzieć na drugą część pytania:
To nie jest nierozsądna rzecz, którą chcesz zrobić. Na przykład Java (gdzie każda metoda jest wirtualna) nie ma problemów z metodami ogólnymi.
Jednym z przykładów w C ++ potrzeby szablonu funkcji wirtualnej jest funkcja członka, która akceptuje ogólny iterator. Lub funkcja składowa, która akceptuje ogólny obiekt funkcji.
Rozwiązaniem tego problemu jest użycie funkcji wymazywania z funkcją boost :: any_range i boost :: function, która pozwoli ci zaakceptować ogólny iterator lub funktor bez potrzeby zmiany funkcji w szablon.
źródło
Istnieje sposób obejścia „wirtualnej metody szablonu”, jeśli zestaw typów dla metody szablonu jest znany z góry.
Aby pokazać pomysł, w poniższym przykładzie użyto tylko dwóch typów (
int
idouble
).Tam metoda „wirtualnego” szablonu (
Base::Method
) wywołuje odpowiednią metodę wirtualną (jedną z nichBase::VMethod
), która z kolei wywołuje implementację metody szablonu (Impl::TMethod
).Wystarczy zaimplementować metodę szablonu
TMethod
w implementacjach pochodnych (AImpl
,BImpl
) i użyćDerived<*Impl>
.Wynik:
NB:
Base::Method
jest faktycznie nadwyżką dla prawdziwego kodu (VMethod
może być upubliczniona i używana bezpośrednio). Dodałem go, aby wyglądał jak rzeczywista metoda „wirtualnego” szablonu.źródło
Base
klasę za każdym razem, gdy musisz wywoływać funkcję szablonu z typem argumentu niezgodnym z tymi, które zostały zaimplementowane do tej pory. Unikanie tej konieczności jest intencją szablonów ...Podczas gdy starsze pytanie, na które wiele osób odpowiedziało, uważam, że zwięzłą metodą, nie różniącą się tak bardzo od innych opublikowanych, jest użycie drobnego makra, aby ułatwić powielanie deklaracji klasowych.
Aby teraz wdrożyć naszą podklasę:
Zaletą tego jest to, że dodając nowy obsługiwany typ, można to wszystko zrobić z abstrakcyjnego nagłówka i zrezygnować z możliwości jego naprawy w wielu plikach źródłowych / nagłówkowych.
źródło
Przynajmniej funkcje wirtualne gcc 5.4 mogą być elementami szablonu, ale same szablony muszą być.
Wyjścia
źródło
Spróbuj tego:
Napisz w classeder.h:
Zaznacz, jeśli pracujesz z tym, aby napisać ten kod w main.cpp:
źródło