Czysta virtual
funkcja musi zostać zaimplementowana w typie pochodnym, który zostanie bezpośrednio utworzony, jednak typ podstawowy nadal może definiować implementację. Klasa pochodna może jawnie wywołać implementację klasy bazowej (jeśli pozwalają na to uprawnienia dostępu) przy użyciu nazwy o pełnym zakresie (przez wywołanie A::f()
w Twoim przykładzie - jeśli A::f()
były public
lub protected
). Coś jak:
class B : public A {
virtual void f() {
// class B doesn't have anything special to do for f()
// so we'll call A's
// note that A's declaration of f() would have to be public
// or protected to avoid a compile time problem
A::f();
}
};
Przypadek użycia, który przychodzi mi do głowy, to mniej lub bardziej rozsądne zachowanie domyślne, ale projektant klas chce, aby takie zachowanie domyślne było wywoływane tylko jawnie. Może być również tak, że chcesz, aby klasy pochodne zawsze wykonywały swoją własną pracę, ale mogły również wywoływać wspólny zestaw funkcji.
Zwróć uwagę, że chociaż język na to zezwala, nie jest to coś, co jest powszechnie używane (a fakt, że można to zrobić, wydaje się zaskakiwać większość programistów C ++, nawet tych doświadczonych).
deported
. (w formacie .inl lub .cpp, aby zapoznać się z typowymi praktykami nazywania plików).Żeby było jasne, nie rozumiesz, co = 0; po funkcji wirtualnej oznacza.
= 0 oznacza, że klasy pochodne muszą zapewniać implementację, a nie, że klasa bazowa nie może zapewnić implementacji.
W praktyce, gdy oznaczysz funkcję wirtualną jako czystą (= 0), podawanie definicji nie ma większego sensu, ponieważ nigdy nie zostanie ona wywołana, chyba że ktoś zrobi to wyraźnie za pośrednictwem Base :: Function (...) lub jeśli Konstruktor klasy bazowej wywołuje daną funkcję wirtualną.
źródło
Zaletą tego jest to, że wymusza typy pochodne, aby nadal zastępowały metodę, ale także zapewnia domyślną lub addytywną implementację.
źródło
Jeśli masz kod, który powinien być wykonywany przez klasę pochodną, ale nie chcesz, aby był wykonywany bezpośrednio - i chcesz wymusić jego zastąpienie.
Twój kod jest poprawny, chociaż w sumie nie jest to często używana funkcja i zwykle widziana tylko podczas próby zdefiniowania czystego wirtualnego destruktora - w takim przypadku musisz zapewnić implementację. Zabawne jest to, że skoro wyprowadzisz z tej klasy, nie musisz nadpisywać destruktora.
Stąd jedynym rozsądnym zastosowaniem czystych funkcji wirtualnych jest określenie czystego wirtualnego destruktora jako „nieostatecznego” słowa kluczowego.
Poniższy kod jest zaskakująco poprawny:
źródło
Na przykład musiałbyś oddać ciało czystemu wirtualnemu destruktorowi :)
Przeczytaj: http://cplusplus.co.il/2009/08/22/pure-virtual-destructor/
(Link uszkodzony, użyj archiwum)
źródło
Tak, to jest poprawne. W naszym przykładzie klasy, które pochodzą od A, dziedziczą zarówno interfejs f (), jak i domyślną implementację. Ale wymusza się na klasach pochodnych implementację metody f () (nawet jeśli jest to tylko wywołanie domyślnej implementacji dostarczonej przez A).
Scott Meyers omawia to w Effective C ++ (2nd Edition) Punkt 36 Rozróżnienie między dziedziczeniem interfejsu a dziedziczeniem implementacji. Numer pozycji mógł ulec zmianie w najnowszym wydaniu.
źródło
Czyste funkcje wirtualne z treścią lub bez niej oznaczają po prostu, że typy pochodne muszą zapewniać własną implementację.
Czyste treści funkcji wirtualnych w klasie bazowej są przydatne, jeśli klasy pochodne chcą wywołać implementację klasy bazowej.
źródło
Funkcja „virtual void foo () = 0;” składnia nie oznacza, że nie możesz zaimplementować foo () w bieżącej klasie, możesz. Nie oznacza to również, że musisz zaimplementować go w klasach pochodnych . Zanim mnie uderzysz, przyjrzyjmy się Diamentowemu Problemowi: (pamiętaj, że ukryty kod).
Teraz wywołanie obj-> foo () spowoduje B :: foo (), a następnie C :: bar ().
Widzisz ... czyste metody wirtualne nie muszą być implementowane w klasach pochodnych (foo () nie ma implementacji w klasie C - kompilator skompiluje) W C ++ jest wiele luk.
Mam nadzieję, że mógłbym pomóc :-)
źródło
C
swoim przykładzie nie można utworzyć wystąpienia obiektu typu . Możesz utworzyć wystąpienie obiektu typu,D
ponieważ pobiera on swoją implementacjęfoo
fromB
.Jednym z ważnych przypadków użycia czystej metody wirtualnej z treścią implementacji jest sytuacja, gdy chcesz mieć klasę abstrakcyjną, ale nie masz w klasie żadnych odpowiednich metod, aby uczynić ją czystą wirtualną. W takim przypadku możesz uczynić destruktor klasy czystym wirtualnym i umieścić w tym celu żądaną implementację (nawet pustą treść). Jako przykład:
Ta technika sprawia, że
Foo
klasa jest abstrakcyjna iw rezultacie nie można jej bezpośrednio utworzyć. Jednocześnie nie dodałeś dodatkowej, czystej metody wirtualnej, aby uczynićFoo
klasę abstrakcyjną.źródło