37

1 つの (デフォルトではない) パラメーターを持つコンストラクターは、そのパラメーターの型からクラスの型に変換する暗黙的なコンバーターのように機能することを理解しています。ただし、explicit任意のコンストラクター、パラメーターを持たないコンストラクター (既定のコンストラクター)、または 2 つ以上のパラメーターを持つコンストラクター (既定以外のコンストラクター) を修飾するために使用できます。

これらのコンストラクターで明示的に許可されているのはなぜですか? これが何らかの暗黙の変換を防ぐのに役立つ例はありますか?

4

5 に答える 5

40

理由の一つは確かに痛くないからです。

必要な理由の 1 つは、最初のパラメーターにデフォルトの引数がある場合です。コンストラクターはデフォルトのコンストラクターになりますが、変換コンストラクターとして引き続き使用できます

struct A {
  explicit A(int = 0); // added it to a default constructor
};

C++0x では、複数パラメーター コンストラクターに実際に使用されます。C++0x では、初期化リストを使用してクラス オブジェクトを初期化できます。哲学は

  • を使用する場合= { ... }は、オブジェクトの抽象的な値を概念的に表し、型に変換したい一種の「複合値」でオブジェクトを初期化します。

  • 初期化子を使用する場合{ ... }、必ずしも変換を指定する必要はなく、オブジェクトのコンストラクターを直接呼び出します。

この例を考えてみましょう

struct String {
    // this is a non-converting constructor
    explicit String(int initialLength, int capacity);
};

struct Address {
    // converting constructor
    Address(string name, string street, string city);
};

String s = { 10, 15 }; // error!
String s1{10, 15}; // fine

Address a = { "litb", "nerdsway", "frankfurt" }; // fine

このように、C++0x は、他のコンストラクターでの明示的な許可を許可するという C++03 の決定が、まったく悪い考えではなかったことを示しています。

于 2010-12-17T04:20:12.687 に答える
7

おそらくそれはメンテナンスをサポートすることでした。explicit複数引数のコンストラクターで使用することにより、引数にデフォルトを追加するときに誤って暗黙の変換を導入することを回避できます。私はそれを信じていませんが; 代わりに、C ++では、言語定義を以前よりも複雑にしないために、多くのことが許可されているだけだと思います。

おそらく最も悪名高いケースは、非staticローカル変数への参照を返すことです。他に影響を与えることなくすべての「無意味な」ものを除外するには、追加の複雑なルールが必要になります。したがって、それは許可されているだけであり、その参照を使用するとUBが生成されます。

または、コンストラクターの場合、署名が異なる限り、任意の数のデフォルトコンストラクターを定義できますが、複数のコンストラクターを使用すると、デフォルトでそれらのいずれかを呼び出すことはかなり困難です。:-)

より良い質問は、おそらく、explicit変換演算子でも許可されないのはなぜですか?

そうですね、C++0xではそうなるでしょう。ですから、そうしない理由はありませんでした。変換演算子を許可しない実際の理由は、見落としのように乱暴であるか、そもそも採用されるのにexplicit苦労している、または委員会の時間の単純な優先順位付けなどである可能性があります。explicit

乾杯&hth。、

于 2010-12-17T03:07:25.273 に答える
7

High Integrity C++ Coding Standard によると、型変換での偶発的な使用を避けるために、すべての単一パラメーター コンストラクターを 明示的 に宣言する必要があります。複数の引数のコンストラクターの場合、複数のパラメーターを受け入れるコンストラクターがあり、それぞれにデフォルト値があり、コンストラクターをある種のデフォルト コンストラクターと変換コンストラクターに変換するとします。

class C { 
    public: 
    C( const C& );   // ok copy 
    constructor C(); // ok default constructor 
    C( int, int ); // ok more than one non-default argument 

    explicit C( int ); // prefer 
    C( double ); // avoid 
    C( float f, int i=0 ); // avoid, implicit conversion constructor 
    C( int i=0, float f=0.0 ); // avoid, default constructor, but 
                               // also a conversion constructor 
}; 
void bar( C const & ); 
void foo() 
{ 
    bar( 10 );  // compile error must be 'bar( C( 10 ) )' 
    bar( 0.0 ); // implicit conversion to C 
}
于 2010-12-17T03:44:05.697 に答える
7

おそらく便利なだけです。許可しない理由はないのに、なぜコードジェネレーターなどの生活を困難にするのでしょうか? チェックした場合、コード生成ルーチンには、生成されるコンストラクターが持つパラメーターの数を確認する追加のステップが必要になります。

さまざまな 情報源によると、厳密に 1 つの引数で呼び出すことができないコンストラクターに適用すると、まったく効果がありません。

于 2010-12-17T02:23:46.463 に答える