COMPILER:g ++ 4.7.2
OK。したがって、_.h
_および_.cpp
_ファイルのデフォルトのパラメーターについて混乱しています。多くの場所(このサイトを含む)で、デフォルトパラメータは.cファイルではなく.hファイルにのみ追加できると言われています。ただし、このコードは間違っていることを証明しています。
test1.h
_#pragma once
#include <iostream>
using namespace std;
class Class{
public:
Class(int, int, int=1);
};
_
test1.cpp
_#include "test1.h"
Class::Class(int a, int b=2, int c)
{
cout<<a<<" "<<b<<" "<<c<<endl;
}
int main()
{
Class a(1);
return 0;
}
_
これで、テストした内容に従って、デフォルトのパラメーターを_.cpp
_ファイルに追加できます。ただし、次の制限が適用されます。
_.cpp
_および_.h
_ファイルに存在するデフォルトのパラメーターは重複してはなりません。つまり、Class(a, b, c=1)
(.hファイル内)およびClass::Class(a,b,c=2)
(.cppファイル内)は無効です。
デフォルトのパラメータが追加されたら、その後に宣言されるすべての変数にもデフォルト値を含める必要があることはよく知られているルールです。これをdefparaルールと呼びましょう。さて、
関数宣言(_.h
_ファイル)に記述されている変数は、defparaルールに従う必要があります。つまり、Class(a, b=2, c)
(.hファイル内)は何に関係なく無効です.cppファイルで宣言されています。
デフォルト値を持つ変数(_.h
_および_.cpp
_ファイルのデフォルト値の共通部分)を考慮すると、defparaルールに従います。つまり、Class(a, b, c=1)
(.hファイル内)およびClass::Class(a,b=2,c)
(_.cpp
_ファイル内)が有効です。ただし、Class(a, b, c=1)
(.hファイル内)およびClass::Class(a=2,b,c)
(_.cpp
_ファイル内)は無効です。
だから....私は正しい、間違っている???
これは、メイン関数がtest.cpp
ファイルにもあるためにのみ機能し、クラスの実装で指定されたデフォルトの引数を参照します。 main
関数をtest.h
のみを含む別のファイルに配置すると、このコードはコンパイルされません。
別の見方をすると、他の一部にtest.h
が含まれている場合、そのコードが見るのはtest.h
で宣言されているものだけなので、他の場所にあるデフォルト引数は使用されません。
関数がヘッダーファイルで宣言されている場合、デフォルトは常にヘッダーファイルに設定する必要があります。
これは、コンパイラがクラスを使用するすべてのコンパイルユニットにヘッダーファイルを使用するためです(「いたずら」で、どこにでもヘッダーファイルを使用しない限り)。
コンパイラーは、関数(この場合はコンストラクター)を呼び出すコードをコンパイルするときにデフォルト引数を追加するため、.cppファイルのデフォルトが何であるかは関係ありません。
もちろん、この場合、ヘッダーファイルの「ユーザー」は1つだけであり、コンストラクターが呼び出される場所は1つだけです。ただし、.cppファイルにデフォルトを設定することは一般に間違っています(ローカル関数でない限り)。
デフォルトを「ミックス」すると、非常に「興味深い」バグが発生します。 .cppに1つのデフォルトがあり、headefileに別のデフォルトがある場合。本当に熟練していれば、関数の呼び出しごとにコンパイラーに異なるデフォルトを生成させることもできます。これは、コードが特定の値であるデフォルトに依存している場合、ほとんど確実に頭痛の種になります。そして、「見やすくするために」デフォルトをヘッダーから.cppファイルにコピーしたくはありません。誰かがデフォルトを変更した場合、ほぼ確実に両方の場所で変更されないか、さらに悪いことに、間違ったデフォルトを変更するため、意図したとおりに動作しません。
.h vs. .cppは赤いニシンです。ルールは、関数の宣言および関数の定義でデフォルト引数を使用できることです。デフォルト引数を同じ値に再定義することはできません。したがって、これは違法です:
void f(int, int = 3);
void f(int, int = 3); // error: redefinition of default argument
ただし、後続の宣言ではデフォルト引数を追加できます。
void f(int, int = 3);
void f(int = 4, int = 3);
f(); // calls f(4, 3);
さらに、関数が呼び出される任意の時点で、その時点で見られたデフォルトの引数を使用できます。
void f(int, int =3);
f(1); // calls f(1, 3);
void f(int = 4, int = 3);
f(1); // calls f(1, 3);
f(); // calls f(4, 3);
元の例では、.hファイルは1つのデフォルト引数を定義し、そのヘッダーを使用するすべての変換ユニットはそのデフォルト引数を使用できます。
Class c3(1, 2, 3);
Class c2(1, 2);
さらに、.cppファイルは追加のデフォルト引数を定義するため、その宣言の後、コンストラクターを1つ、2つ、または3つの引数で呼び出すことができます。
Class c3(1, 2, 3);
class c2(1, 2);
class c1(1);
C++のファイル定義のデフォルトパラメータなどはありません。宣言内にのみ存在します。
コンパイラーは、後者のパラメーターが欠落している関数を検出します。これらがデフォルトの場合、関数呼び出しにこれらのパラメーターが含まれているかのように、関数を呼び出すオブジェクトコードを作成するために空白を埋めることができます。
PS: Item 38/Scott Myers/Effective C++-継承されたデフォルトのパラメーター値を再定義しないでください。