2012-02-23 10 views
4

私はこのような何かを達成したい:クラスの属性値をメソッドの既定のパラメーターとして使用する代わりに、

非静的メンバは、デフォルト引数

に使用してはならない:C++標準が言うように、これは不可能です

class C 
{ 
    int m_nVal; 
public: 
    C(int nVal) : m_nVal(nVal){}    

    void foo(int nVal = m_nVal) 
    { 
     // use nVal, if provided; otherwise use m_nVal 
    } 
}; 

C c(1); 
c.foo(); // use 1 
c.foo(2); // use 2 

私が持っているオプション:

(1)オーバーロードfoo()

class C 
{ 
    int m_nVal; 
public: 
    C(int nVal) : m_nVal(nVal){} 

    void foo() 
    { 
     // use m_nVal 
    } 

    void foo(int nVal) 
    { 
     // use nVal 
    } 
}; 

(2)静的メンバを使用します

class C 
{ 
    static int m_nVal; 
public:   
    void foo(int nVal = m_nVal) 
    { 
     // use nVal, if provided; otherwise use m_nVal 
    } 
}; 

を私はm_nVal静的メンバをしたくないので、オプション1は、一つだけのようです。

これを達成する他の方法はありますか?

+4

これは過負荷が*のために作られたものといえます。 – Jon

+0

foo(int nval)に関してfoo()を呼び出すだけです。 – Jagannath

+0

私はポインタと 'nullptr'をデフォルト値として使うのはオプションではないと思いますか? –

答えて

5

インターフェイスを変更したい場合は、他の方法があります。あなたはboost::optionalを使用することができます。

// untested: 
void foo(boost::optional<int> val = boost::optional<int>()) { 
    int value; 
    if (val) value = *val; 
    else value = m_val; 
    // Now use `value` in the function 
} 

あなたはブーストを使用することができない場合は、あなたがあなた自身のNULL可能ラッパーを書くことができます。タイプ(int)と、それが設定されているかどうかを決定するフラグを格納するだけです。

次のオプションは、引数がオプションであることをマークするために、ポインタを使用している:

void foo(int *pval = 0) { 
    int value = (pval? *pval : m_val); 
    // use value from here on 
} 

しかし、ポインタを持つオプションは、関数の引数として右辺値の使用を禁止する(あなたは正しいが必要、すなわち、関数を呼び出す変数は、foo(1)を実行することはできませんが、むしろint x = 1; foo(&x);を実行する必要があります。これは痛みの一種です)。

最後に、2つのオーバーロード、最初にないとだけ転送しない引数と1をとるものを提供するというあなたのアプローチを使用することができます。

void foo(int val) { 
    // actual implementation 
} 
void foo() { 
    foo(m_val); 
} 

これは実際には最良の選択肢かもしれません...

+0

残念ながら、Boostはオプションではありません(私の決定ではありません)。私はポインタのアイデアが気に入っていますが、あなたが注目したように、このインターフェイスはクライアントには見えません(オブジェクト自体の代わりにポインタを渡します)。私は過負荷と一緒に行きます。 –

2

2つのオプションは同等ではありません。メンバをstaticにすることは、それをメソッドのデフォルトとして使用するかどうかを決定するべきではありません。

m_nValがインスタンスではなくクラスに論理的にバインドされている場合は、staticにします。

m_nValがクラスの各オブジェクトに固有の場合は、最初のオプションを使用しないでください。

+0

完全に同意します。 'static'は最初からオプションではありませんでした。私はそれが一般的な問題を解決しているにすぎないということを上に挙げました(ただし、クラスデザインに合わない場合は特にありません)。 –

+0

@BojanKomazec私は過負荷で行くだろう、他のすべてはちょうど私に過度のようだ。 –

+0

ええ、それは最も直感的なアプローチのようです。お手伝いありがとう。 –

0
class C 
    { 
     int m_nVal; 
    public: 

     C(int nVal) : m_nVal(nVal){}    

     void foo(int nVal = -1) 
     { 
     if(nVal == -1) 
      nVal = m_nVal; 

      // use nVal, if provided; otherwise use m_nVal 
     } 
    }; 

C c(1); 
c.foo(); // use 1 
c.foo(2); // use 2 
+0

これはひどいです、 'foo(-1)'を呼びたいのですが?あなたがdownvotedを取得する前に、私はこれを削除します。 –

+0

私は実際には、特定の値が有効でないことが分かっている多くのドメインでは、セントリとして使用できると考えています。たとえば、引数が負でないことが分かっている場合、これがオプションになります。私はどちらもアップアップしていないだろうが、ドメインに応じて何ができるかを補うために+1する。 –

+0

@DavidRodríguez-dribeasなぜパラメータが 'unsigned int'でないのですか? –

0

デフォルトのパラメータを渡すと、コンパイラはそれを渡す必要があります。つまり、m_nValの場合、コンパイラはthis->m_nValを使用します。これは `foo(this-> m_nVal); 'を意味します。

これは私が何を意味するかです:m_nValプライベートデータは、クラス外部からアクセスすることができるようになる

c.foo(c.m_nVal); // use 1 

、および基本的なC++のルールを破ります。

+0

アクセスはフィールドにpublicを指定することでテストできますが、アクセスは許可されていますが、どちらもコンパイルされません。 –

+0

@Ajayこれは実際に私がコードのリファクタリングを考え始めた理由です - 'm_nVal'は現在公開されており、私はそれを隠したいと思います。もう一つは、 'foo'が引数として' c.m_nVal'で最も頻繁に呼び出されるため、デフォルト値として使用することを考え始めました。 –

+0

はい、プライベートで保護されていますが、これは許されない理由の1つです。 – Ajay

関連する問題