Mam klasę bazową z funkcją wirtualną i chcę przesłonić tę funkcję w klasie pochodnej. Czy istnieje sposób, aby kompilator sprawdzał, czy funkcja, którą zadeklarowałem w klasie pochodnej, faktycznie przesłania funkcję w klasie bazowej? Chciałbym dodać jakieś makro lub coś, co zapewnia, że nie zadeklarowałem przypadkowo nowej funkcji, zamiast nadpisać starą.
Weź ten przykład:
class parent {
public:
virtual void handle_event(int something) const {
// boring default code
}
};
class child : public parent {
public:
virtual void handle_event(int something) {
// new exciting code
}
};
int main() {
parent *p = new child();
p->handle_event(1);
}
Here parent::handle_event()
jest wywoływana zamiast child::handle_event()
, ponieważ metoda dziecka pomija const
deklarację i dlatego deklaruje nową metodę. Może to być również literówka w nazwie funkcji lub niewielka różnica w typach parametrów. Może się to również łatwo zdarzyć, jeśli interfejs klasy bazowej zmieni się i gdzieś jakaś klasa pochodna nie zostanie zaktualizowana, aby odzwierciedlić zmianę.
Czy jest jakiś sposób na uniknięcie tego problemu, czy mogę w jakiś sposób powiedzieć kompilatorowi lub innemu narzędziu, aby to sprawdził? Jakieś pomocne flagi kompilatora (najlepiej dla g ++)? Jak uniknąć tych problemów?
Odpowiedzi:
Od wersji g ++ 4.7 rozumie nowe
override
słowo kluczowe C ++ 11 :źródło
override
należy użyć @ h9uest . Implementacja inline to zarówno definicja, jak i implementacja, więc to jest w porządku.Coś takiego jak
override
słowo kluczowe C # nie jest częścią C ++.W gcc
-Woverloaded-virtual
ostrzega przed ukrywaniem funkcji wirtualnej klasy bazowej za pomocą funkcji o tej samej nazwie, ale z wystarczająco inną sygnaturą, aby jej nie przesłaniała. Nie ochroni cię to jednak przed niepowodzeniem nadpisania funkcji z powodu błędnej pisowni samej nazwy funkcji.źródło
override
słowa kluczowego w C ++; może to jednak oznaczać, że używasz czegoś, co może skompilować jakiś nieprawidłowy kod źródłowy C ++. ;)override
funkcjonalność w stylu C # ; Rzadko miałem problemy z nieudanymi zastąpieniami i były one stosunkowo łatwe do zdiagnozowania i naprawienia. Myślę, że nie zgodzę się z tym, że użytkownicy VC ++ powinni go używać. Wolałbym, żeby C ++ wyglądał jak C ++ na wszystkich platformach, nawet jeśli jeden konkretny projekt nie musi być przenośny. Warto zauważyć, że C ++ 0x będzie miał[[base_check]]
,[[override]]
i[[hiding]]
atrybutów, dzięki czemu można zdecydować się, by przesłonić sprawdzania w razie potrzeby.override
słowo kluczowe wydaje się, że tak . Cóż, nie jest to właściwe słowo kluczowe, ale specjalny identyfikator w C ++ 11. Microsoft naciskał wystarczająco mocno, aby zrobić specjalny przypadek i zastosować ogólny format atrybutów ioverride
wprowadził go do standardu :)O ile wiem, czy nie możesz po prostu uczynić tego abstrakcyjnym?
Myślałem, że przeczytałem na www.parashift.com, że faktycznie można zastosować metodę abstrakcyjną. Co dla mnie osobiście ma sens, jedyne, co robi, to wymusza na podklasach implementację, nikt nie powiedział nic o tym, że nie może mieć samej implementacji.
źródło
BaseClass::method()
wywołaniu metody podstawowej (powiedzmy ) w implementacji pochodnej (powiedzmyDerivedClass::method()
), np. Dla wartości domyślnej.W MSVC możesz użyć
override
słowa kluczowego CLR, nawet jeśli nie kompilujesz dla CLR.W przypadku g ++ nie ma bezpośredniego sposobu na wymuszenie tego we wszystkich przypadkach; inni ludzie udzielili dobrych odpowiedzi na temat tego, jak wychwycić różnice w sygnaturach za pomocą
-Woverloaded-virtual
. W przyszłej wersji ktoś mógłby dodać składnię taką jak__attribute__ ((override))
lub jej odpowiednik, używając składni C ++ 0x.źródło
W MSVC ++ możesz użyć słowa kluczowego
override
override
działa zarówno dla kodu natywnego, jak i CLR w MSVC ++.źródło
Uczyń funkcję abstrakcyjną, tak aby klasy pochodne nie miały innego wyboru, jak tylko ją przesłonić.
@Ray Twój kod jest nieprawidłowy.
Funkcje abstrakcyjne nie mogą mieć obiektów zdefiniowanych w tekście. Musi zostać zmodyfikowany, aby stał się
źródło
Sugerowałbym niewielką zmianę w twojej logice. To może działać lub nie, w zależności od tego, co musisz osiągnąć.
handle_event () może nadal wykonywać „nudny kod domyślny”, ale zamiast być wirtualnym, w miejscu, w którym chcesz, aby wykonał „nowy ekscytujący kod”, wywołaj metodę bazową metodą abstrakcyjną (tzn. należy ją przesłonić) które zostaną dostarczone przez twoją klasę potomną.
EDYCJA: A jeśli później zdecydujesz, że niektóre z Twoich klas potomnych nie muszą dostarczać „nowego ekscytującego kodu”, możesz zmienić abstrakcję na wirtualną i podać pustą implementację klasy bazowej tej „wstawionej” funkcjonalności.
źródło
Twój kompilator może mieć ostrzeżenie, które może wygenerować, jeśli funkcja klasy bazowej zostanie ukryta. Jeśli tak, włącz go. Spowoduje to wykrycie konfliktów const i różnic w listach parametrów. Niestety to nie ujawni błędu pisowni.
Na przykład jest to ostrzeżenie C4263 w programie Microsoft Visual C ++.
źródło
Słowo
override
kluczowe C ++ 11 użyte z deklaracją funkcji wewnątrz klasy pochodnej zmusza kompilator do sprawdzenia, czy zadeklarowana funkcja faktycznie przesłania jakąś funkcję klasy bazowej. W przeciwnym razie kompilator zgłosi błąd.Dlatego możesz użyć
override
specyfikatora, aby zapewnić dynamiczny polimorfizm (przesłanianie funkcji).źródło