2012-08-27 72 views
18

我創建了一個抽象基類,它具有帶默認參數的純虛擬方法。最佳做法:純虛擬方法的缺省參數

class Base { 
    ... 
    virtual someMethod(const SomeStruct& t = 0) = 0; 
    ... 
} 

class Derived : public Base { 
    ... 
    virtual someMethod(const SomeStruct& t = 0); 
    ... 
} 

所以我想知道它是一個很好的做法,默認參數設置爲純虛和整體虛擬方法呢?

+3

我想你的意思是const SomeStruct * t = 0? – marcinj

+4

@luskan:'SomeStruct'可以隱式地從'0'轉換。 –

+0

「將默認參數設置爲純虛擬」意味着什麼? –

回答

13

我常常希望像你一樣同時使用默認參數和虛擬功能。然而其他人卻正確地指出,這導致含糊不清,通常不是一個好主意。有一個相當簡單的解決方案,我使用。給你的虛擬函數一個不同的名字,使它受到保護,然後用默認的參數提供一個公用函數來調用它。

class Base { 
protected: 
    virtual void vSomeMethod(const SomeStruct& t) = 0; 
public: 
    void someMethod(const SomeStruc& t = 0) 
    { vSomeMethod(t); } 
} 

派生類只需覆蓋vSomeMethod而且不用擔心在所有關於默認參數。

+4

與其引入另一個名稱「vSomeMethod」,爲什麼不使用重載?即添加一個公共的非虛擬成員函數'void someMethod()'到調用'someMethod(0);'的'Base'。在更普遍的情況下,你需要一個虛擬成員函數'f(xn,...,x1,x0)',它可以用'n + 1'默認參數值調用,'xn = vn,...,x1 = v1,x0 = v0','f'的虛擬過載可能沒有默認值,並且可能會有'n'默認參數'f(xn = vn,...,x1 = v1) '調用'f(xn,...,x1,v0)'。 – Ose

+2

@Ose使用單獨命名的實現函數而不是重載相同名稱的原因是,當您覆蓋子類中的虛擬實現時,將隱藏非父虛擬助手,要求您另外使用該方法進入孩子。 –

6

都儘量不要使用默認參數,但如果這樣做,從來不會重新定義它們(see the text for details

都買了有效的C++的書斯科特邁爾斯。你不會後悔的。

+0

我在這兩種方法中設置了相同的默認值,我認爲您的引用是關於不同值可以設置爲默認參數時的ambiguouse情況。 – deimus

+0

deimus,真的沒關係。即使你_think_你將總是使用與默認參數相同的值,那麼犯一個錯字或者忘記提供一個默認參數是非常容易的。調試這種錯誤將使你的生活真正悲慘與任何適當的代碼庫。 –

+2

@deimus你不能保證將來有人不會繼承你的基類並改變默認值。 – juanchopanza

27

實際上,您的代碼是默認參數中可能最差的使用模式之一,因爲它涉及繼承和多態行爲。我支持建議看看相關的Scott Meyers提示,但這裏有一個簡短的概述:

在多態調用的情況下,根據靜態類型聲明使用默認參數,而不是動態類型。這是合乎邏輯的,因爲運行時間不知道默認參數,但是打破了關於多態行爲的任何理智假設。例如,

#include <cstdio> 

class Base 
{ 
     public: 
       virtual void f(int a = 1) 
       { 
         printf("Base::f(%d)\n", a); 
       } 
}; 

class Deriv : public Base 
{ 
     public: 
       virtual void f(int a = 2) 
       { 
         printf("Deriv::f(%d)\n", a); 
       } 
}; 

int main() 
{ 
     Base* a = new Deriv(); 
     a->f(); 
     delete a; 
     return 0; 
} 

產量:

Deriv::f(1) 
+0

很好的例子,顯示了與這種方法相關的陷阱。 –

+1

您的示例讓我大惑不解,+1 – asimes

0

我將:

  • 定義與參數的虛擬功能(沒有默認值)
  • 在 所有定義的基類非虛函數,不帶參數,調用傳遞的虛擬功能正確的默認參數

這樣派生類根本就不用關心默認值。

0

如果你想這個代碼意義:

Base* p = new Derived; 
p->someMethod(); 

因爲靜態類型的pBase*這是在調用中使用的基本特徵。 分配了默認值,並且作爲虛函數,呼叫被重定向到派生。

你甚至可以讓他們不同的定義,如果你想你的派生::的someMethod從Base*而不是Derived*收到不同的值...

重要的是這些文件「關係」好了,既然大多數程序員通過簡單閱讀代碼就無法理解它們。

當然,如果所有這些都是不適合你特定情況下,比其他產生更多的混亂,避免虛函數的默認參數,並使用輔助非虛擬一個正確地調用它們。

但也考慮到-by讀者standpoint-默認參數大於過載函數調用私下另一個具有不可讀取參數返工更explicative。