C++には「変換コンストラクター」または「変換コンストラクター」と呼ばれるものがあると聞きました。これらは何であり、何のためですか?このコードに関して言及されているのを見ました:
class MyClass
{
public:
int a, b;
MyClass( int i ) {}
}
int main()
{
MyClass M = 1 ;
}
変換コンストラクターの定義は、C++ 03とC++ 11で異なります。どちらの場合でも、それは非explicit
コンストラクタでなければなりません(そうでなければ、暗黙の変換には関与しません)が、C++ 03の場合、単一の引数で呼び出し可能でなければなりません。あれは:
_struct foo
{
foo(int x); // 1
foo(char* s, int x = 0); // 2
foo(float f, int x); // 3
explicit foo(char x); // 4
};
_
コンストラクター1および2は、どちらもC++ 03およびC++ 11のコンストラクターを変換しています。 2つの引数を取る必要があるコンストラクター3は、C++ 11の変換コンストラクターのみです。最後のコンストラクタ4は、explicit
であるため、変換コンストラクタではありません。
C++ :§12.3.1
単一のパラメーターで呼び出すことができるfunction-specifier
explicit
なしで宣言されたコンストラクターは、最初のパラメーターの型からの変換を指定しますクラスの型に。このようなコンストラクターは、変換コンストラクターと呼ばれます。
C++ 11:§12.3.1
function-specifier
explicit
なしで宣言されたコンストラクターは、パラメーターの型からクラスの型への変換を指定します。このようなコンストラクターは、変換コンストラクターと呼ばれます。
複数のパラメーターを持つコンストラクターがC++ 11のコンストラクターを変換していると見なされるのはなぜですか?これは、新しい標準がbraced-init-listsを使用して引数を渡し値を返すための便利な構文を提供するためです。次の例を考えてみましょう。
_foo bar(foo f)
{
return {1.0f, 5};
}
_
戻り値をbraced-init-listとして指定する機能は、変換と見なされます。これは、foo
とfloat
を取るint
の変換コンストラクターを使用します。さらに、bar({2.5f, 10})
を実行してこの関数を呼び出すことができます。これも変換です。それらは変換であるため、使用するコンストラクターがコンストラクターを変換することは理にかなっています。
したがって、foo
とfloat
をとるint
のコンストラクターをexplicit
関数指定子にすると、上記が停止することに注意することが重要です。コンパイルからのコード。上記の新しい構文は、ジョブを実行するために利用可能な変換コンストラクターがある場合にのみ使用できます。
C++ 11:§6.6.3:
braced-init-listを含む
return
ステートメントは、copy-list-initializationによって関数から返されるオブジェクトまたは参照を初期化します(8.5.4)指定された初期化子リストから。
§8.5:
[...]を渡す引数で[...]で発生する初期化は、コピー初期化と呼ばれます。
§12.3.1:
明示的コンストラクターは、非明示的コンストラクターと同様にオブジェクトを構築しますが、直接初期化構文(8.5)またはキャスト(5.2.9、5.4)が明示的に使用される場合にのみオブジェクトを構築します。
コンストラクタを変換して暗黙的に変換する
質問の例をもっと複雑にしましょう
class MyClass
{
public:
int a, b;
MyClass( int i ) {}
MyClass( const char* n, int k = 0 ) {}
MyClass( MyClass& obj ) {}
}
最初の2つのコンストラクターはコンストラクターを変換しています。 3番目はコピーコンストラクターであり、それ自体が別の変換コンストラクターです。
変換コンストラクターは、引数型からコンストラクター型への暗黙的な変換を可能にします。ここで、最初のコンストラクターは、int
からクラスMyClass
のオブジェクトへの変換を有効にします。 2番目のコンストラクターは、文字列からクラスMyClass
のオブジェクトへの変換を有効にします。 3番目...クラスMyClass
のオブジェクトからクラスMyClass
のオブジェクトへ!
コンストラクターを変換するには、コンストラクターに単一の引数(2番目の引数、2番目の引数に1つのデフォルト値)があり、キーワードexplicit
なしで宣言する必要があります。
次に、mainの初期化は次のようになります。
int main()
{
MyClass M = 1 ;
// which is an alternative to
MyClass M = MyClass(1) ;
MyClass M = "super" ;
// which is an alternative to
MyClass M = MyClass("super", 0) ;
// or
MyClass M = MyClass("super") ;
}
明示的なキーワードとコンストラクター
では、explicit
キーワードを使用した場合はどうなりますか?
class MyClass
{
public:
int a, b;
explicit MyClass( int i ) {}
}
次に、コンパイラは受け入れません
int main()
{
MyClass M = 1 ;
}
これは暗黙的な変換であるためです。代わりに、書く必要があります
int main()
{
MyClass M(1) ;
MyClass M = MyClass(1) ;
MyClass* M = new MyClass(1) ;
MyClass M = (MyClass)1;
MyClass M = static_cast<MyClass>(1);
}
explicit
キーワードは、コンストラクターの暗黙的な変換を防ぐために常に使用され、クラス宣言のコンストラクターに適用されます。
変換コンストラクターは、関数指定子explicitなしで宣言される単一パラメーターコンストラクターです。コンパイラは、変換コンストラクターを使用して、オブジェクトを最初のパラメーターの型から変換コンストラクターのクラスの型に変換します。