2013-07-02 16 views
5

Tak więc, opierając się na pobieżnym wyszukiwaniu, już wiem, że wywołanie funkcji wirtualnej (czystej lub innej) z konstruktora nie jest możliwe. Przebudowałem swój kod, aby upewnić się, że tego nie robię. Chociaż to powoduje, że użytkownik moich klas może dodać dodatkowe wywołanie funkcji w swoim kodzie, to naprawdę nie jest to wielka sprawa. Mianowicie, zamiast wywoływać konstruktora w pętli, nazywają teraz funkcję, która (w rzeczywistości!) Zwiększa wydajność kodu, ponieważ nie mamy za zadanie budowania i niszczenia danego obiektu za każdym razem.Wywołanie funkcji czystej wirtualnej z funkcji członka abstrakcyjnej bazy klasy?

Mam jednak natknął się coś ciekawego ...

w abstrakcyjnej klasie mam coś takiego:

// in AbstractClass.h: 
class AbstractClass { 
public: 
    AbstractClass() {} 
    virtual int Func(); //user can override 
protected: 
    // Func broken up, derived class must define these 
    virtual int Step1() = 0; 
    virtual int Step2() = 0; 
    virtual int Step3() = 0; 
// in AbstractClass.cpp: 
int AbstractClass::Func() { 
    Step1(); 
    // Error checking goes here 
    Step2(); 
    // More error checking... 
    // etc... 
} 

Zasadniczo istnieje wspólna struktura, która czyści funkcje wirtualne śledzić najbardziej czasu, ale jeśli nie, funkcja Func() jest wirtualna i umożliwia klasie pochodnej określenie kolejności. Jednak każdy krok musi być zaimplementowany w klasach pochodnych.

Po prostu chciałem mieć pewność, że nie ma niczego, co koniecznie robię źle tutaj, ponieważ funkcja Func() nazywa czyste wirtualne. Oznacza to, że przy użyciu klasy bazowej, jeśli wywołasz StepX(), złe rzeczy się zdarzą. Jednak klasa jest wykorzystywana przez tworzenie obiektu pochodnego, a następnie wywoływanie Func() (np. MyDerivedObject.Func();) na tym obiekcie pochodnym, który powinien mieć wszystkie czyste funkcje wirtualne przeciążone poprawnie.

Czy jest coś, czego mi brakuje lub robię nieprawidłowo, postępując zgodnie z tą metodą? Dzięki za pomoc!

+1

To jest podręcznikowy przykład używania idiomu [Non-Virtual Interface idiom] (http://en.wikipedia.org/wiki/Non-virtual_interface_pattern) do implementacji [Wzorca metody szablonów] (http: // en. wikipedia.org/wiki/Template_pattern). – Casey

+0

Aby wyjaśnić, istnieje duża różnica między "wywoływaniem funkcji wirtualnych w konstruktorze" i "wywoływaniem funkcji czysto wirtualnych". Ten pierwszy jest podchwytliwy i zniechęcony (choć ważny), drugi jest całkowicie błędny (a także nie całkiem trywialny). –

+0

Wywołanie funkcji wirtualnej w konstruktorze lub destruktorze nie jest "nie do przyjęcia", chyba że nie zawracasz sobie głowy zrozumieniem, jak działają. –

Odpowiedz

4

Func wywołuje wirtualne, a nie czyste wirtualne. Będziesz musiał zakwalifikować wywołania za pomocą operatora zasięgu, tj. AbstractClass :: Step1(), aby wywołać funkcję THAT (virtual pure). Ponieważ nie jesteś, zawsze otrzymasz implementację przez klasę pochodną.

+0

Więc bez względu na to, co robię, chyba że zrobię coś NAPRAWDĘ hacky jak AbstractClass :: Step3(), funkcje będą nadpisane przez klasy pochodnej? Czy są jakieś czerwone flagi z tym podejściem w odniesieniu do dobrych praktyk kodu C++? –

+3

To właśnie sprawia, że ​​OO i C++ są potężne. Możesz napisać "procedury", w których klasa pochodna ma określić szczegóły. Pomyśl o protokole komunikacyjnym. EstablishConnection(); podczas(!Done()) {SendRequest(); GetResponse();} TerminateConnection(); Wszystkie te metody mogą być "wirtualne", jedna klasa pochodna używa TCP, inna wykorzystuje nawet wyższy poziom mechanizmu "połączenia" lub prostszy punkt do punktu Protokół RS-232 nie ma nic w swoich metodach Establish/TerminateSession(). Zdefiniowałeś jednak małe ramy, które można łatwo wdrożyć i rozszerzyć. – franji1

+0

Dzięki za wyjaśnienie. Jestem dość nowy w niektórych z tych koncepcji OO i chcę być tak ostry jak to możliwe ... –

1

Funkcja wirtualna w klasie bazowej sprawia, że ​​klasy pochodne mogą ją przesłonić. Ale wydaje się, że wszystko się kończy.

Ale jeśli funkcja wirtualna klasy podstawowej jest czysta, wymusza to, że klasy pochodne implementują tę funkcję.

-1

Jako komentarz boczny można wykonać metody Step1, Step2, Step3 jako prywatne, aby uniemożliwić kompilatorowi bezpośrednie wywoływanie ich.

+1

Powinien być komentarzem? – lpapp

Powiązane problemy