2010-01-13 13 views
6

Czy jest jakiś problem z częściowym przesłonięciem zestawu funkcji wirtualnych zdefiniowanych przez klasę podstawową?Problemy z nadpisaniami funkcji częściowej klasy w języku C++

Moje kompilator daje następujące ostrzeżenie:

overloaded virtual function "MyBaseClass::setValue" is only partially overridden in class "MyDerivedClass". 

Klasy wyglądać następująco:

class MyBaseClass 
{ 
public: 
    virtual void setValue(int); 
    virtual void setValue(SpecialType*); 
} 

class MyDerivedClass : public MyBaseClass 
{ 
public: 
    virtual void setValue(int); 
} 

Prosty sposób, aby pozbyć się tego ostrzeżenia może używać różnych nazw dla funkcji bazowych, ale chciałem wiedzieć, czy istnieje jakiś nieodparty powód, aby naprawić to ostrzeżenie. Nie wierzę, że to narusza standard C++. Domyślam się, że jest to ostrzeżenie programisty, że może on zapomniał wprowadzić zachowanie dla wszystkich możliwych typów danych wejściowych. W naszym przypadku celowe jest wyłączenie niektórych konkretnych typów.

Czy odradzasz całkowicie ignorowanie tego ostrzeżenia?

+0

Jeśli rozważasz użyciu różnych nazw dla funkcji bazowych, za wszelką cenę zrobić. Sugeruje mi to, że MyBaseClass :: setValue (int) robi inną koncepcyjną rzecz z MyDerivedClass :: setValue (int), a to jest złe. Funkcje wirtualne powinny robić to samo w bazie i wyprowadzane, lub można uzyskać trudne do znalezienia błędy z drobnych zmian. –

+0

W moim konkretnym przypadku koncepcyjnie robią to samo. Zmiana nazwy mogła być podobna do setValueFromInt() setValueFromSpecialType(), która nie wyglądałaby tak czysto. Zdecydowanie wolałbym używać instrukcji użycia opisanych w jednej z odpowiedzi. Obecnie badam wdrażanie tego podejścia. –

Odpowiedz

13

Korekcja dla setValue(int) ukrywa setValue(SpecialType*) klasy bazowej (patrz C++ FAQ Lite), więc jeśli spróbujesz zadzwonić setValue(new SpecialType()) dostaniesz błąd.

Można tego uniknąć poprzez dodanie dyrektywę using do klasy pochodnej że „import” z przeciążeniami z klasy bazowej:

class MyDerivedClass : public MyBaseClass 
{ 
public: 
    using MyBaseClass::setValue; 
    virtual void setValue(int); 
}; 
+0

+1 za pokazanie, jak NIE przepisywać wersji, które nie są zainteresowane specjalizowaniem. –

+0

Używanie instrukcji działa dla mnie. Pracuję dla wielu platform. Mam problem ze zwróceniem Microsoft Visual Studio 6.0, aby złożyć skargę na ten konkretny problem z kodem. Nawet przy najsurowszym poziomie ostrzegania nie mogę go zmusić do złożenia skargi. Ktoś z pomysłem, jak uzyskać ten kompilator, aby wypluć ostrzeżenie? –

6

Ostrzeżenie jest prawidłowe, nazywa się "ukrywanie imienia". Zmienna typu MyDerivedClass nie może wywołać setValue(SpecialType*).


Teraz mam zamiar rażąco zdzierać someone else's blog:

Przeciążenie i nazwa ukrywa się w C++

W rozmowie telefonicznej z Brad ostatniej nocy, powiedział mi o dziwnym problem napotkał w swojej nowej pracy w C++. To prawda, że ​​to chyba nic wielkiego dla osób z dużym doświadczeniem w C++, ale dla tych z nas, którzy żyją w zarządzanych światach kodu, wydawało się to dziwne.

W języku C++, gdy masz klasę z metodą przeciążenia (funkcja składowa, cokolwiek chcesz na nią nazywać), a następnie rozszerzasz i zastępujesz tę metodę, musisz zastąpić wszystkie przeciążone metody.

Rozumiem przypadek, w którym zmieniono sygnaturę metody w klasie potomnej, tym samym unieważniając ustanowiony interfejs. W tym przypadku jednak wydaje się to sprzeczne z intuicją, ponieważ nie zmieniasz interfejsu, ale wybiórczo nadpisujesz. Który jest inny.

Na przykład

class FirstClass 
{ 
public: 
     virtual void MethodA (int); 
     virtual void MethodA (int, int); 
}; 

void FirstClass::MethodA (int i) 
{ 
    std::cout << "ONE!!\n"; 
} 

void FirstClass::MethodA (int i, int j) 
{ 
    std::cout << "TWO!!\n"; 
} 

Klasa prosta o dwóch metod (lub jeden przeciążony metody). Chcesz nadpisać wersję dwóch parametrów, więc nadal z następujących czynności:

class SecondClass : public FirstClass 
{ 
public: 
    void MethodA (int); 
}; 

void SecondClass::MethodA (int i) 
{ 
    std::cout << "THREE!!\n"; 
} 

Teraz, gdy używasz wystąpienie secondClass większość Java lub C# programiści mogą zakładać można nazwać:

int main() 
{ 
    SecondClass a; 
    a.MethodA (1); 
    a.MethodA (1, 1); 
} 

jednak drugie połączenie nie będzie działać, ponieważ dwuparametrowego sposób A nie jest widoczny. Możesz otrzymać wskaźnik i up-cast do FirstClass, ale twoja instancja SecondClass nie dziedziczy bezpośrednio metod, które nie zostały zastąpione.

0

To jasne, że kompilator chce cię ostrzec: utworzono podklasę że zachowuje się inaczej, podając go pod int, ale nie zmieniłeś jego zachowania, podając go pod SpecialType*.

Chociaż to może być intencją, jest bardzo możliwe, że zmienione zachowanie jest również potrzebne w przypadku innych przeciążonych funkcji wirtualnych.

Żałuję, że kompilator nie ostrzegł mnie bardziej, gdy go zignorowałem! Moja nadpisana metoda okazała się być kompilowana i działała dobrze w moim scenariuszu, ale niektóre inne scenariusze poszły naprawdę źle, ponieważ przeciążenie nie zostało przesłonięte.

Zastanów się dwa razy, zanim wyłączysz ostrzeżenie!

Jeśli chcesz oryginalne zachowanie utrzymane, łatwo jest po prostu wywołać funkcję nadrzędny:

class MyDerivedClass : public MyBaseClass { 
    virtual void setValue(int); 
    // explicit: keep original behavior for SpecialType 
    virtual void setValue(SpecialType* p) { MyBaseClass::setValue(p); } 
}; 
+0

Rozumiem, że ostrzeżenia są ważne i próbują ostrzec mnie o czymś, co może pójść nie tak. Celem mojego pytania było ustalenie, dlaczego ostrzeżenie jest ważne dla projektanta i jakie pułapki mogą wystąpić poprzez ignorowanie/wyciszanie go. –

Powiązane problemy