2010-07-06 42 views
2

我有一個默認的int&參數(如iNewArgument)在頭文件添加到現有的函數定義:如何使用帶有默認值的int&參數?

什麼是初始化的最後一個參數,使其取默認值的語法?

.. 
virtual int ExecNew 
    (int& param1, int& RowIn,int& RowOut, char* Msg = '0', 
      bool bDebug=true, int& iNewArgument = NULL) = 0 ; 
. 
. 

NULL已經#defined 0

Error: default argument: cannot convert from int to int&

+3

如果你希望它能夠爲null,那麼你需要一個指針而不是引用。 – 2010-07-06 22:10:44

+0

我與邁克在這。請參閱[我的答案](http://stackoverflow.com/questions/3190571/c-int-reference-question/3190603#3190603)。 – sbi 2010-07-06 22:18:58

+0

我拿回來(我刪除了我的答案)。除了約翰尼斯,每個人都忽略了「虛擬」。爲虛擬函數設置默認參數並不是一個好主意。 – sbi 2010-07-06 22:29:46

回答

9

你的例子表明你正在創建一個虛函數。虛擬(特別是純粹)函數中的默認參數不是一個好主意,因爲在調用重寫函數時不會考慮它們。現在

struct A { 
    virtual void f(int = 4711) = 0; 
}; 

struct B : A { 
    virtual void f(int) { /* ... */ } 
}; 

,如果有人一B對象調用f,他將提供的說法 - 不使用默認值。您必須在派生類中重複默認參數,這會產生醜陋的冗餘。相反,你可以使用非虛擬接口模式

struct A { 
    void f(int a) { 
    int out; 
    f(a, out); 
    } 

    void f(int a, int &out) { 
    doF(a, out); 
    } 

protected: 
    virtual void doF(int a, int out&) = 0; 
}; 

用戶現在可以用一個叫f,並有兩個參數,無論從任何類類型他所說的功能,和A實施者沒有擔心默認的參數。通過使用重載而不是默認參數,你不需要圍繞左值或臨時值。

+0

哦,大家都忽略了這個!好,趕上,約翰內斯,'+ 1'從我身上。 (而且,順便說一句,如果'B :: f()'有一個不同的默認參數,它會更加嚴重 - 代碼默默編譯,但是具有不同的語義! – sbi 2010-07-06 22:27:46

1

你不能做到這一點。 INewArgument必須是一個原始int或一個const引用。無法以您嘗試使用它的方式使用非const引用。

1

總之,你將不得不重做你的問題。你可以使int成爲一個常規的int並且失去參考行爲(能夠傳遞改變的值)或者放棄具有默認值。

+0

再次查看您的示例代碼,您正在嘗試使用INewArgument傳遞一個指針,而不是引用。在這種情況下,這是您的另一種選擇:傳遞一個指針而不是引用。如果你不介意使用指針,它會很好用。 – 2010-07-06 22:12:31

1

對於非const引用類型,缺省值必須是左值,所以上面的嘗試不起作用。你可以做的是:

namespace detail { 
    int global; 
} 

void foo(int &x = detail::global) {} 

void bar(const int &x = int(3)) {} 
+0

對於你的第一種情況:'NULL'作爲「我沒有你的參數」是普遍理解的,'detail :: global'不是。對於第二種情況:應該對每個副本採用內置插件,而不是每個「const」引用。 – sbi 2010-07-06 22:25:07

+0

第二個變體對於更復雜的數據類型仍然有用,例如void foo(const std :: set &x = std :: set ()),這有時是有道理的。 – Staffan 2010-07-06 22:29:05

4

提供一個默認的參數傳遞給一個非const引用的唯一有意義的方法是定義一個獨立的對象具有靜態存儲時間和使用它作爲默認參數

int dummy = 0; 

... 
virtual int ExecNew(/* whatever */, int& iNewArgument = dummy) = 0; 

它是否會爲您工作是由您來決定。

在函數內部,如果你需要檢測是否使用了默認參數,你可以使用地址比較

if (&iNewArgument == &dummy) 
    /* Default argument was used */ 
+0

如果在函數內部比較地址,那麼這表示函數應該爲每個引用取這個對象。如果地址對函數的語義很重要,則調用者應該可以看到它。 – sbi 2010-07-06 22:21:26

+0

@sbi:在這種特殊情況下,地址被視爲一個沒有接口含義的實現細節。將該實現細節公開給用戶是不正確的。然而,我只是補充說,在最好的情況下,應該選擇默認參數,以便(函數被設計成使得)函數不需要檢測已經使用了默認參數的事實。 – AnT 2010-07-06 22:30:50

1

你說NULL是#defined爲0,所以這是一個文字值。該參數是對int的引用,這意味着該函數將能夠更改該值。你如何改變文字的價值?

您需要將其作爲const參考,或者根本不要將其作爲參考。