web-dev-qa-db-ja.com

C ++でデフォルトのパラメータ値をどこに置くか

デフォルトのパラメータ値の場所は?関数の定義、宣言、またはその両方にありますか。

283
Thomson

デフォルトのパラメータ値は、呼び出し側に表示される唯一のものであるため、宣言に表示する必要があります。

EDIT:他の人が指摘しているように、あなたはcan定義に議論を持っています、しかし私はそれが真実ではないかのようにすべてのコードを書くことを勧めます。

288
Marcelo Cantos

どちらでもできますが、両方はできません。通常は関数の宣言時に行い、その後すべての呼び出し側がそのデフォルト値を使用できます。しかし 代わりに関数定義でそれを行うことができます そして定義を見る人だけがデフォルト値を使うことができるでしょう。

91
sharptooth

最も有用な場所は宣言(.h)の中にあるので、すべてのユーザーがそれを見ることができます。

実装にデフォルト値を追加することを好む人もいます(コメントとして)。

void foo(int x = 42,
         int y = 21);

void foo(int x /* = 42 */,
         int y /* = 21 */)
{
   ...
}

しかし、これは重複を意味し、コメントがコードと同期していない可能性があります(コメントされていないコードより悪いのは、誤解を招くコメントのあるコードです)。

77
6502

これは「古い」スレッドですが、それでも以下を追加したいと思います。

私は次のケースを経験しました:

  • クラスのヘッダファイルでは、
int SetI2cSlaveAddress( UCHAR addr, bool force );
  • そのクラスのソースファイルでは、
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force = false )
{
   ...
}

ご覧のとおり、パラメータ "force"のデフォルト値は、クラスヘッダファイルではなくクラスソースファイルに入れました。

次に、その関数を派生クラスで次のように使用しました(派生クラスはパブリッククラスで基本クラスを継承しました)。

SetI2cSlaveAddress( addr );

「force」パラメータを「false」として「当然」と見なすと仮定します。

しかし、コンパイラ(をc ++ 11モードにすると)が文句を言って、次のようなコンパイラエラーが発生しました。

/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp: In member function 'void CMax6956Io::Init(unsigned char, unsigned char, unsigned int)':
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: error: no matching function for call to 'CMax6956Io::SetI2cSlaveAddress(unsigned char&)'
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: note: candidate is:
In file included from /home/geertvc/mystuff/domoproject/lib/i2cdevs/../../include/i2cdevs/max6956io.h:35:0,
                 from /home/geertvc/mystuff/domoproject/lib/i2cdevs/max6956io.cpp:1:
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: int CI2cHal::SetI2cSlaveAddress(unsigned char, bool)
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note:   candidate expects 2 arguments, 1 provided
make[2]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/max6956io.cpp.o] Error 1
make[1]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/all] Error 2
make: *** [all] Error 2

しかし、基本クラスのヘッダーファイルにデフォルトのパラメータを追加した場合は、次のようになります。

int SetI2cSlaveAddress( UCHAR addr, bool force = false );

そして、基本クラスのソースファイルからそれを削除しました:

int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force )

それからコンパイラは満足していて、すべてのコードは期待通りに動きました(私は1つか2つのパラメータを関数SetI2cSlaveAddress()に与えることができました)!

ですから、クラスのユーザにとってだけではなく、パラメータのデフォルト値をヘッダファイルに入れることが重要です。コンパイルと機能的にも、それは明らかに必須のようです。

37
GeertVc

関数が公開されている場合(非メンバ、パブリック、または保護されている場合)、呼び出し元はそれらについて知っている必要があり、デフォルト値必須がヘッダーにあります。

関数がプライベートでアウトオブラインである場合、デフォルトを実装ファイルに入れることは理にかなっています。なぜならそれはクライアントの再コンパイルを引き起こさない変更を可能にするからです。開発)。そうは言っても、それは間違いなく混乱を招く可能性があり、ヘッダーにもっと直感的な方法でAPIを表示することにドキュメントの価値があるので、妥協を選択してください。

13
Tony Delroy

宣言は一般的に最も「有用」ですが、それはあなたがクラスをどのように使いたいかによって異なります。

両方とも無効です。

10
justin

良い質問です...私は、コーダーは通常、デフォルトを宣言するために宣言を使用することに気付きました。私は、コンパイラに基づいて、一方向(または警告された)または他の方法に拘束されました。

void testFunct(int nVal1, int nVal2=500);
void testFunct(int nVal1, int nVal2)
{
    using namespace std;
    cout << nVal1 << << nVal2 << endl;
}
10
ice911

私がだれも言及していないもう1つのポイント

仮想メソッドがある場合は、各宣言に独自のデフォルト値を設定できます。

どの値が使用されるかは、呼び出しているインターフェースによって異なります。

ideone の例

struct iface
{
    virtual void test(int a = 0) { std::cout << a; }
};

struct impl : public iface
{
    virtual void test(int a = 5) override { std::cout << a; }
};

int main()
{
    impl d;
    d.test();
    iface* a = &d;
    a->test();
}

50を印刷します

このように使うことを強くお勧めします

9
relaxxx

どちらでも構いません(標準に従って)。ただし、デフォルト引数を含む定義の前に、デフォルト引数なしの宣言がコード内にある場合は、コンパイルエラーが発生する可能性があります。

たとえば、デフォルトの引数リストなしで関数宣言を含むヘッダを含めると、デフォルトの引数値が認識されず、プロトタイプが一致しないため、コンパイラはそのプロトタイプを検索します。

デフォルトの引数で関数を定義に入れているのなら、そのファイルをインクルードしてください。しかし私はそれをお勧めしません。

3
Pervez Alam

もう1点追加します。デフォルトの引数を使用した関数宣言は、右から左へおよび上から下へにする必要があります。

以下の関数宣言で宣言の順序を変更すると、コンパイラはデフォルトのパラメータが足りないというエラーを表示します。コンパイラが、同じ有効範囲内でデフォルト引数を使用して関数宣言を分離できるようにする理由は、RIGHTからLEFT(デフォルト引数)、そしてTOPからBOTTOM(関数宣言のデフォルト引数の順序)の順です。

//declaration
void function(char const *msg, bool three, bool two, bool one = false);
void function(char const *msg, bool three = true, bool two, bool one); // Error 
void function(char const *msg, bool three, bool two = true, bool one); // OK
//void function(char const *msg, bool three = true, bool two, bool one); // OK

int main() {
    function("Using only one Default Argument", false, true);
    function("Using Two Default Arguments", false);
    function("Using Three Default Arguments");
    return 0;
}

//definition
void function(char const *msg, bool three, bool two, bool one ) {
    std::cout<<msg<<" "<<three<<" "<<two<<" "<<one<<std::endl;
}
3
SridharKritha