web-dev-qa-db-ja.com

C ++の変換コンストラクタとは何ですか?それは何のため?

C++には「変換コンストラクター」または「変換コンストラクター」と呼ばれるものがあると聞きました。これらは何であり、何のためですか?このコードに関して言及されているのを見ました:

class MyClass
{
  public:
     int a, b;
     MyClass( int i ) {}
}

 int main()
{
    MyClass M = 1 ;
}
43
kiriloff

変換コンストラクターの定義は、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-specifierexplicitなしで宣言されたコンストラクターは、最初のパラメーターの型からの変換を指定しますクラスの型に。このようなコンストラクターは、変換コンストラクターと呼ばれます。

  • C++ 11:§12.3.1

    function-specifierexplicitなしで宣言されたコンストラクターは、パラメーターの型からクラスの型への変換を指定します。このようなコンストラクターは、変換コンストラクターと呼ばれます。

複数のパラメーターを持つコンストラクターがC++ 11のコンストラクターを変換していると見なされるのはなぜですか?これは、新しい標準がbraced-init-listsを使用して引数を渡し値を返すための便利な構文を提供するためです。次の例を考えてみましょう。

_foo bar(foo f)
{
  return {1.0f, 5};
}
_

戻り値をbraced-init-listとして指定する機能は、変換と見なされます。これは、foofloatを取るintの変換コンストラクターを使用します。さらに、bar({2.5f, 10})を実行してこの関数を呼び出すことができます。これも変換です。それらは変換であるため、使用するコンストラクターがコンストラクターを変換することは理にかなっています。

したがって、foofloatをとる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)が明示的に使用される場合にのみオブジェクトを構築します。

53

コンストラクタを変換して暗黙的に変換する

質問の例をもっと複雑にしましょう

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キーワードは、コンストラクターの暗黙的な変換を防ぐために常に使用され、クラス宣言のコンストラクターに適用されます。

15
kiriloff

変換コンストラクターは、関数指定子explicitなしで宣言される単一パラメーターコンストラクターです。コンパイラは、変換コンストラクターを使用して、オブジェクトを最初のパラメーターの型から変換コンストラクターのクラスの型に変換します。

1
Fazail awan