9

Explicitlyコンストラクターとの両方を呼び出すことができるという概念を知っておりImplicitly、両方のシナリオをテストしました(通常、これまではコンストラクターを呼び出すことですべての目的が達成されましたImplicitly)が、作成するたびにコンストラクターが暗黙的に呼び出されるのではobjectsないかと思っていました。コンストラクターを呼び出す主な理由Explicitly。コンストラクターを呼び出すときに、どのような長所または短所がExplicitlyありImplicit Callますか?

class integer
{
   int m ,n;
 public:
   integer (int x , int y); 
};
integer :: integer (int x , int y )
{
   m=x; n = y;
}

今私が好きなように呼ぶなら

integer int1 = integer( 0 , 100); //  Explicit Call
integer int1(1,100); // implicit call
4

5 に答える 5

20

明示的および暗黙的の定義が標準定義と一致しないため、ここには2つの異なる問題があります(既存の回答のほとんどが基づいており、明示的および暗黙的の独自の定義を含む例を追加する前に記述されています)。

では、最初に明示的な定義について考えてみましょう。これは、(型名を明示的に記述しているため、明示的に呼んでいると思いますか?

integer int1 = integer(0, 100);

対暗黙の定義は次のようになります。

integer int1(1, 100);

この場合、最初の「明示的な」呼び出しは、実際には2番目の「暗黙的な」呼び出しに勝る利点はありません。しかし、まだ違いがあります。最初のものは、実際には2つの引数のコンストラクターを使用して一時的なものを作成し、次にint1コピーコンストラクターを使用して作成するために使用されます。実際には、コンパイラは通常、この追加のコピーを最適化しますが、コピーコンストラクタがプライベートの場合は機能しませんが、2番目のコンストラクタは2つの引数のコンストラクタのみを必要とします(これは不利と見なされることもあります)。


しかし、ここで、明示的および暗黙的なの実際の標準定義について説明します。明示的なコンストラクター呼び出しとは、明示的に呼び出すコンストラクター呼び出しです。実際には、括弧構文()を使用してオブジェクトを作成する場合は常に、コンストラクターを明示的に呼び出します。それ以外の場合は、暗黙的なコンストラクター呼び出しです(つまり、コンパイラーによってバックグラウンドで実行されます)。

integer int1;                   // implicit default constructor
integer int1(1, 100);           // explicit two-arg constructor
integer int1 = integer(0, 100); // explicit two-arg constructor, implicit copy constructor

void func(integer);             // function taking by-value
func(int1);                     // implicit copy constructor

したがって、暗黙的に呼び出すことができるコンストラクターは、デフォルトのコンストラクターと任意の1つの引数のコンストラクター(コピーおよび移動コンストラクターを含む)のみです。この点に関する特別な問題は、1つの引数のコンストラクターがコピー/移動コンストラクターではないことです。

struct integer
{
    integer(int);
};

これにより、コンパイラーはコンストラクターを暗黙的に呼び出して型を変換できるため、int暗黙的に次のように変換できintegerます。

void func(integer);
func(42);             // implicit call to int-constructor

このような動作を禁止するには、コンストラクターにマークを付ける必要がありますexplicit

struct integer
{
    explicit integer(int);
};

これは、明示的に呼び出すことだけを許可します(たとえばfunc(integer(42)))(しかし、あなたはすでにこれを知っていると思います)。これには、バックグラウンドで見過ごされたり不要な変換が発生したりすることがないという利点があります。これにより、過負荷の解決に関するあらゆる種類の見つけにくい問題やあいまいさが生じる可能性があります。したがって、変換コンストラクター(1引数の非コピー/移動コンストラクター)をマークするのが通常の方法であり、おそらくC++11が最終的に変換演算子explicitを導入した理由でもあります。explicit


したがって、要約すると、あなたの定義と例によれば、(通常は無関係な)違いはありますが、integer int1 = integer(1, 100);の代わりに使用することに実際には利点はありません。integer int1(1, 100);

しかし、標準の定義によれば、明示的なコンストラクター呼び出しは暗黙的なコンストラクター呼び出しよりも多くの利点があります。オブジェクトを明示的に構築する唯一の方法は、明示的なコンストラクター呼び出しを使用することですが、暗黙的なコンストラクター呼び出しは特定の舞台裏でのみ実行されるためです。状況に応じて、引数が0および1のコンストラクターでのみ機能します(asheplerがすでに指摘しているように)。また、変換コンストラクターを明示的にマークexplicitすることには、不要な暗黙の変換をバックグラウンドで禁止するという利点があります。

于 2012-08-20T13:21:33.263 に答える
2

コンストラクターを呼び出すと、デフォルトのコンストラクターを使用するのではなく、引数を使用してオブジェクトを明示的に作成できます。

class Foo
{
  public:
    Foo() {}
    Foo(int bar) : mBar(bar) {}
  private:
    int mBar;
}

Foo f;    // Implicitly constructed with default constructor.
Foo f(7); // Explicitly constructed with argument for 'bar'
于 2012-08-20T10:32:26.840 に答える
2

コンストラクターを呼び出す方法は3つあります。

  • 暗黙的に、型を初期化せずに型のインスタンスを宣言することによって
  • また、暗黙的に、インスタンスを初期化するか=、引数タイプからクラスへの暗黙的な変換を引き起こします。
  • コンストラクターを明示的に呼び出し、引数を渡します。

特定のコンテキストでこれらのどれを使用できるかは、呼び出しているコンストラクターによって異なります。

class Foo 
{
    Foo();                                  // 1
    Foo(int a);                             // 2
    explicit foo(const std::string& f);     // 3
    Foo(int c, int d);                      // 4
};
  1. このコンストラクターは、を宣言するときに暗黙的に呼び出されFoo f;ます。関数を宣言するように、引数なしでコンストラクターを明示的に呼び出そうとしないでください。Foo f();
  2. Foo f = 42;これは、またはを書くことによって呼び出すことができますFoo f(42)
  3. キーワードは、またはexplicitを書くことによる暗黙の変換を禁止します。Foo f = std::string("abc");function_taking_foo(function_returning_string());
  4. 複数の引数があるため、明示的なバージョンが唯一の適切なものです。
于 2012-08-20T10:42:17.787 に答える
1

非常にひどいので、私はこれを言うのは嫌ですが、コンストラクターを明示的に呼び出す追加の方法があります。

class integer
{
   int m ,n;
 public:
   integer (int x , int y); 
};
integer :: integer (int x , int y )
{
   m=x; n = y;
}

コンストラクターは、既に構築されたオブジェクトに対して明示的に呼び出すことができます。

integer i(1,100);
i.~integer();
i.integer::integer(2,200);

ここで、整数のインスタンスを(明示的に)作成しました。次に、そのデストラクタを明示的に呼び出しました。次に、コンストラクターを再度明示的に呼び出しました。テストでこのイディオムを使用するかもしれないと思います。私はそれを禁止している規格のどこにも気づいていません。VisualStudio2010で動作します。私は実際に広範囲のコンパイラをテストしていません。

これらの呼び出しは、'explicit'の大きな値に対して明示的です。

于 2015-09-02T19:02:28.313 に答える
0

クラスのオブジェクトへの参照を取得する関数を作成し、それをオブジェクト以外の別の型に渡すと、クラスのコンストラクターがその型をクラスのオブジェクトに変換します。1つの引数コンストラクターは、変換コンストラクターとして扱われます。コンストラクターを明示的に宣言した場合、オブジェクト以外の別の型をその関数に渡しても変換されず、コンパイラーはエラーを返します。

于 2012-08-20T10:39:15.703 に答える