2012-11-08 53 views
5

我假設函數已經有一個返回值,所以不能被添加。如何在不破壞現有代碼的情況下將輸出參數添加到函數中?

我想出來解決這個問題是添加額外的指針參數,默認爲nullptr。

前:

bool fun(double a, std::vector<std::randomexample> const & b) 

後:

bool fun(double a, std::vector<std::randomexample> const & b, int* extraoutput = nullptr) 

,並使用它像這樣

if(extraoutput) 
    *extraoutput = whatever; 

但是,這僅僅是我想出了。 我想知道是否有更好的方法來做到這一點。請注意,「無論」已經在該功能中。

+1

似乎合理。 –

+1

如果您絕對不想更改現有的東西,請創建一個新的重載的東西。 –

回答

4

如果由於某種原因,你需要二進制以及(大部分)的源代碼兼容[*]:

前:

bool fun(double a, std::vector<std::randomexample> const & b) { 
    // do stuff 
    return true; 
} 

後:

bool fun(double a, std::vector<std::randomexample> const & b, int* extraoutput) { 
    // do stuff 
    if(extraoutput) 
     *extraoutput = whatever; 
    return true; 
} 
bool fun(double a, std::vector<std::randomexample> const & b) { 
    return fun(a, b, nullptr); 
} 

如果您不希望函數重載(例如,如果funextern "C" i的一部分nterface),那麼你實際上不必調用新函數fun。它可以是fun2

[*]正如AndreyT指出的那樣,您的解決方案的源代碼兼容性是有限的。調用你的舊函數會很好地調用你的新函數,但是你可能用舊函數做的其他一些事情將不會正常工作(因爲你改變了它的類型)。

我的代碼中實際上存在源不兼容問題。允許在添加重載之前允許使用void(*foo)() = (void(*)()) fun;,但之後不確定。如果你想支持這樣做的代碼,那麼這是不想讓函數重載的第二個原因。

+0

爲什麼舊功能的類型會改變?我的意思是,舊功能現在只是調用新功能,所以內容似乎已經改變,但我不明白爲什麼類型改變。 – Sarien

+0

@Corporal:你函數的類型'bool fun(double a,Foo const&b)'是'bool(double,Foo const&)'。你的函數'bool fun(double a,Foo const&b,int * extraoutput = nullptr)'的類型是'bool(double,Foo const&,int *)'。兩者不一樣。在我的代碼中,除了新函數之外,還有一個類型爲'bool(double,Foo const&)'*的函數,所以依賴於舊類型的代碼是OK。 –

+0

啊,好的,所以這不是你的解決方案中的問題,而是我的問題。對不起,感到困惑。 :) – Sarien

-1

您可以嘗試實現泛型觀察者模式。 這是一個像: http://sourcemaking.com/design_patterns/observer

這將是更好的未來,當你想要添加更多的參數。如果你不能派生,那麼作爲參數傳遞也是解決方案。

據我所知你必須在這個功能,否則是超載是一個很好的解決方案。

它沒有打破二進制可壓縮性,否則其他解決方案。

+1

這與現在的情況真的有關嗎? –

+0

更通用的解決方案始終是一種情況,我認爲未來會有更多參數進入遊戲。 – CyberGuy

+0

@Cthulhu:可以。現在添加一個可選的新參數,該參數目前具有'observewhatever'功能。當同樣的事情再次發生時,您不必爲該函數添加*另一個可選的指針參數,您可以添加另一個函數給觀察者。 –

0

正如別人所說,這將是您的最終產品。

bool fun(double a, std::vector<std::randomexample> const & b){ 
    return fun(a,b,0); 
} 
bool fun(double a, std::vector<std::randomexample> const & b, int* extraoutput = 0){ 
    // have fun! 
    if(extraoutput) *extraoutput = whatever; 
    return true; 
} 
+0

爲什麼默認參數? – xtofl

+1

在這種情況下,您必須刪除默認參數,否則帶有2個參數的調用將變得不明確。 – AnT

+0

也許最好在新函數中創建額外的輸出並將其作爲參考傳遞。可能能夠保存一些複製,並且通話不會再模糊。 – Sarien

2

通常情況下,我添加的方法與額外的參數,並調用一個具有缺省值從以前的方法:

//foo v1 
void foo(S s) { 
    ... stuff with s; 
}; 

//codeA_v1: 
S s; 
foo(s); 

//codeB_v1 
S s2; 
foo(s2); 

然後,我添加一個方法有一個額外的參數:

void foo(S s){ foo(s, default_value_for_T); } 
void foo(S s, T t){ 
    ... stuff with s and t 
} 

//codeA_v1 == codeA_v2 
S s; 
foo(s); 

//codeB_v2 
S s; 
T t; 
foo(s,t); 
2

這是一個擴展的評論。正如其他人建議的那樣,爲了提供源代碼和二進制兼容性,你最好重載函數。這樣做的原因是通過引入功能簽名的改變,你也改變了損壞的符號名稱,例如,從_Z3fundRKSt6vectorISt13randomexampleSaIS0_EE_Z3fundRKSt6vectorISt13randomexampleSaIS0_EEPi。這會破壞所有其他調用fun()舊對象的對象的二進制兼容性。如果fun()是動態鏈接庫的一部分,它將打破與其鏈接的所有現有二進制文件,因爲動態鏈接程序將不再能夠解析_Z3fundRKSt6vectorISt13randomexampleSaIS0_EE符號引用。如果使用重載的函數版本,舊的符號將仍然存在,並保留二進制兼容性。

相關問題