2008-11-03 43 views
9

我有一個基類帶有可選的虛擬函數帶有參數錯誤練習的非純虛函數?

class Base { 
    virtual void OnlyImplementThisSometimes(int x) {} 
}; 

當我編譯此,我收到了關於未使用PARAM X警告。有沒有其他方式我應該實現虛函數?我已經重新編寫這樣的:

class Base { 
    virtual void OnlyImplementThisSometimes(int x) 
    { 
     x = 0; 
    } 
}; 

我也有這個問題,如果我不小心,我讓子類可以實現錯誤的函數,然後我千萬不要因爲超載的通知:例如

class Derived : public Base { 
    void OnlyImplementThisSometimes(int x, int y) { // some code } 
}; 

Derived d; 
Base *b = dynamic_cast<Base *>(&d); 
b->OnlyImplementThisSometimes(x); // calls the method in the base class 

基類方法被調用是因爲我用「int y」參數實現派生函數,但沒有關於此的警告。這些只是C++常見的陷阱,還是我誤解了虛函數?

回答

22

忽略的設計問題,你可以省略變量名繞開有關未使用的變量的編譯器警告,例如:

virtual void OnlyImplementThisSometimes(int) { } 

試圖重寫虛函數時誤執行了錯誤的方法簽名只是你需要在C++中小心一些。像C#這樣的語言通過'override'關鍵字解決了這個問題。

+1

執行此操作的另一種方法(相同效果)是將內聯變量名註釋掉,例如:int/* x * /。如果變量名稱是描述性的(它應該是),這將有助於讀者。 – Nick 2008-11-04 02:32:35

+0

@尼克:我堅信強類型安全,類型描述的目的(並防止爭論混亂)。如果你(大多數)這樣的代碼,參數名稱並不重要。 – 2011-12-12 14:00:10

+0

可以編輯最後一段以反映C++中的「override」關鍵字。 – Rotem 2016-05-29 08:03:57

6

爲什麼要在基類中定義它?如果基類不打算使用該方法,則只需在派生類中將其定義爲虛方法即可。

或默認的實現可能拋出一個異常

4

如果你提供了一個虛函數的默認實現,這應該是所有派生類不重寫功能的正確實施。如果你不能提供正確的實現,那麼我的建議是製作一個純虛擬函數,並將其留給派生類來提供實現。不允許調用方法的派生類可以拋出異常,以確保它不會被錯誤地使用。

+0

如果你能想到一個通常是正確的實現,但並不總是如此,那麼你可以提供一個純虛函數的實現,並且在正常情況下派生類只是調用它。 – 2008-11-04 13:06:51

2

這在我的代碼中有點常見。例如,我有專爲單線程操作和多線程設計的類。有很多常見的例程和數據。我把所有這些都放在基類中(它也有一些純虛擬的)。我在基類中實現了兩個空虛擬函數:Init()和Cleanup()。單線程派生類不會提示它們,但多線程派生類可以。

我有一個工廠函數創建approprite派生類然後返回一個指針。客戶端代碼只知道基類的類型,它調用Init()和Cleanup()。兩種情況都是正確的。

當然,如何做到這一點可能還有其他好的建議,但是這個習語很適合我的代碼。

+0

我相信,在派生類中重寫一個純虛函數,並使其不做任何事情會導致代碼更清晰和更容易使用,而不是在基類中執行此操作,而不是在派生類中重寫。誤用的可能性較小,因爲該課程的用戶必須仔細考慮。 – foraidt 2008-11-04 00:43:54

3

除了簡單地省略了變量名,在許多編譯器,你可以告訴編譯器,你都知道,它是由這樣

int func(int x) 
{ 
    (void) x; 
} 
+0

嚴格來說,這並不會告訴編譯器它沒有被使用和SHUTUP。它使用它。 – 2008-11-04 13:08:41

2

這不是一個不好的做法使用,仍在SHUTUP,這是一個指定實現可選的類的部分的常見習慣用法。

目前我正在使用它作爲用戶輸入系統,因爲對於該類的用戶來說,實現每一種方法都是很乏味的,即使它很可能也不會使用它。

class mouse_listener{ 
public: 
    virtual ~mouse_listener() {} 

    virtual void button_down(mouse_button a_Button) {} 
    virtual void button_up(mouse_button a_Button) {} 
    virtual void scroll_wheel(mouse_scroll a_Scroll) {} 
    virtual void mouse_move_abs(math::point a_Position) {} 
    virtual void mouse_move_rel(math::point a_Position) {} 
}; 
2

順便說一句,如果你知道你的基類,從未有任何需要做動態 -casts,即來源於基地。

Base *b = &d; 

會做一樣好,dynamic_cast<>應該改爲使用時,你得到的向下轉換,即從基地:

if((Derived *d = dynamic_cast<Derived *>(b)) != 0) 
{ 
    // use d 
} 

(當然在向下轉換的情況下,static_cast<>將平時工作也一樣)

+0

我至少可以考慮一個需要動態強制轉換的情況:如果您從模板參數派生,並且需要根據基本類型調用特定的函數。在我的情況是這樣的:if(fixture * f = dynamic_cast (this)){f-> set_up();} – 2008-11-04 03:44:54

11

我們定義一個宏_unused爲:

#define _unused(x) ((void)x) 

然後定義功能:

virtual void OnlyImplementThisSometimes(int x) { _unused(x);} 

這不僅能保持從抱怨編譯器,但這樣的確明顯,任何人都保持你還沒有忘記X代碼 - 你是故意忽略它。

-2

最簡單的答案是如下圖所示:

class Base { 
    virtual void OnlyImplementThisSometimes(int x) { x;} 
}; 

一個簡單的參考,其(在最高水平從VC++反正)絕對沒有將刪除所有警告變量。

-1

試試這個:

class Base { 
    virtual void OnlyImplementThisSometimes(int x) = 0; 
}; 

這已經有一段時間,因爲我已經做了類似的東西,但我相信這是你如何聲明一個虛函數。

也如其他人所說,變量名在這樣的函數聲明中是可選的。