1. 程式人生 > >為什麼不能使用成員變數的值作為成員函式的預設引數?

為什麼不能使用成員變數的值作為成員函式的預設引數?

在解決工作中遇到一個問題時,我定義了一個類c(如下所示),包含兩個功能類似的公共查詢介面Rate()和Rate(char bs_flag, char sh_flag),二者的區別是,在例項化物件的時候,會包含bs_flag和sh_flag,因此我希望有一個不用指定查詢條件的Rate函式,用來反映預設情形;但有時又需要變更查詢條件查詢,如第二個指定查詢條件的Rate函式,那麼能否將這兩個函式合併呢?

class CFeeSettings
{
public:
    CFeeSettings(const CFeesParas &s);
    double Rate();
    double Rate(char bs_flag, char sh_flag);
private:
	// ... 
};

我想到三個辦法:

第一,定義一個設定查詢條件的函式SetCond(char bs_flag, char sh_flag),然後將帶引數的查詢介面Rate去掉,如下面所示:

class CFeeSettings
{
public:
    CFeeSettings(const CFeesParas &s);
    double Rate();
    void Set(char bs_flag, char sh_flag);
private:
	// ... 
};
但是這樣做會很麻煩,每次查詢條件有變化之時,在呼叫Rate之前,都要呼叫Set,程式碼將不清晰且冗餘;

第二,去掉無參查詢介面Rate:

class CFeeSettings
{
public:
    CFeeSettings(const CFeesParas &s);
    double Rate(char bs_flag, char sh_flag);
private:
	// ... 
};
這樣的話,即使查詢條件不變更,也必須輸入條件,仍然不簡潔;

第三,使用預設引數:

class CFeeSettings
{
public:
    CFeeSettings(const CFeesParas ¶s);
    double Rate(char bs_flag=m_bs_flag, char sh_flag=m_sh_flag);
private:
	// ... 
	char m_bs_flag;
	char m_sh_flag;
};

本以為這樣可以了,但竟然報了編譯錯誤,苦思無解之餘,不得已求助於網路,在stackoverflow上搜索一通之後,終於在此處找到了答案:

原來,如果要在成員函式中使用成員變數作為預設引數時違反C++標準的:

Default arguments are evaluated each time the function is called. 
The order of evaluation of function arguments is unspecified. 
Consequently, parameters of a function shall not be used in default argument expressions, even if they are not evaluated.

此時我們關注第二行的內容:函式引數解析順序是未指定的。

對於我們的成員函式來講,如果定義為void f(int a=m_a);那麼實際上f的實現為void f(X* this, int a=this->m_a);由於標準未規定a先初始化還是this先初始化,所以這樣做是不允許的。

--

後記:雖然問題的解決辦法還沒找到,但至少堵上了一條不可行之路。