2010-01-13 21 views
6

部分覆蓋由基類定義的一組虛函數是否存在問題?C++中部分類函數覆蓋的問題

我的編譯器提供了以下警告:

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

的類是這樣的:

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

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

最簡單的方法來擺脫這種警告是爲基函數使用不同的名稱,但我想知道是否有任何令人信服的理由來解決這個具體的警告。我不相信這違反了C++標準。我的猜測是,它警告程序員他們可能忘記爲所有可能的輸入類型實現行爲。在我們的案例中,有意排除某些特定類型。

你會不打算壓制這個警告嗎?

+0

如果您使用不同的名稱爲基礎的功能考慮,通過各種手段做到這一點。這表明MyBaseClass :: setValue(int)從MyDerivedClass :: setValue(int)做了一個不同的概念事情,這很糟糕。虛擬功能應該在基礎和派生中執行相同的事情,或者您可以通過較小的更改獲得難以發現的錯誤。 – 2010-01-13 15:46:53

+0

在我的具體情況下,他們在概念上做同樣的事情。重命名可能是像setValueFromInt()setValueFromSpecialType()這看起來不乾淨。我更願意使用其中一個答案中描述的using語句。目前正在調查實施該方法。 – 2010-01-13 16:34:33

回答

13

setValue(int)的倍率隱藏基類(見C++ FAQ Lite)的setValue(SpecialType*),因此,如果您嘗試調用setValue(new SpecialType()),你會得到一個錯誤。

您可以通過添加一個using指令派生類避免這一點,「進口」從基類的重載:

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

+1實際上顯示瞭如何不重寫您不感興趣專業版的版本。 – 2010-01-13 19:00:46

+0

使用聲明適用於我。我正在開發多個平臺。我無法讓Microsoft Visual Studio 6.0抱怨這個特定的代碼問題。即使有最嚴格的警告級別,我也無法得到它的抱怨。任何人有一個想法如何讓這個編譯器吐出警告? – 2010-01-21 22:43:15

6

該警告是正確的,它被稱爲「名稱隱藏」。 MyDerivedClass類型的變量不能撥打setValue(SpecialType*)


現在我要公然撕掉 someone else's blog

超載名躲藏在C++

在與布拉德昨晚的電話交談,他告訴我一個奇怪的他在新C++作業中遇到的問題。誠然,對於擁有廣泛C++經驗的人來說,這可能沒什麼大不了的,但對於我們這些生活在託管代碼世界的人來說,這似乎很奇怪。在C++中,當你有一個帶有重載方法(成員函數,無論你想調用它的類)的類,然後擴展並覆蓋該方法時,必須覆蓋所有重載方法。

我瞭解您在子類中更改方法簽名的情況,從而使已建立的接口無效。但是,在這種情況下,這似乎違反直覺,因爲你不改變界面,但有選擇地重寫。這是不同的。

例如:

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"; 
} 

簡單類這裏有兩個方法(或一個重載方法)。要覆蓋這兩個參數的版本,讓你繼續下面的:

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

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

現在,當你用二等的一個實例,大多數Java或C#程序員可能會認爲你可以撥打:

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

然而,第二個電話都不行,因爲這兩個參數的治法是不可見的。您可以獲得一個指針並將其上傳至FirstClass,但您的SecondClass實例不會直接繼承未覆蓋的方法。

0

很明顯,編譯器要提醒你:你創建了一個子類,在給予int時的行爲會有所不同,但在給予SpecialType*時並未改變其行爲。

儘管此可能是是意圖,但其他重載虛擬函數也需要改變的行爲。

我希望編譯器提醒我更加困難,我忽略它!我重寫的方法證明在我的場景下編譯和工作得很好,但是由於過載沒有被覆蓋,其他一些場景變得非常錯誤。

在禁用該警告之前請三思!

如果你想在原來的行爲保留,很容易只需要調用父功能:

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

我明白,警告是重要的,並試圖警告我可能出錯的事情。我的問題的目的是要找出爲什麼警告對設計師來說很重要,而忽略/消除它會產生什麼缺陷。 – 2010-01-13 16:43:30