1

私の c++ の本 (lippman、c++ 入門書、第 5 版、p. 508) では、コンパイラがいつコピー コントロールと既定のコンストラクターを削除されたメンバーとして合成するかを判断するための次の 4 つの規則を提供しています。

  • 合成されたデストラクタは、削除された、またはアクセスできない (private などの) デストラクタを持つメンバーがクラスにある場合、削除済みとして定義されます。

  • クラスに、独自のコピー コンストラクターが削除されているかアクセスできないメンバーがある場合、合成されたコピー コンストラクターは削除済みとして定義されます。クラスに、削除されたデストラクタまたはアクセスできないデストラクタを持つメンバーがある場合も削除されます。

  • メンバーに削除された、またはアクセスできないコピー代入演算子がある場合、またはクラスに const または参照メンバーがある場合、合成されたコピー代入演算子は削除済みとして定義されます。

  • クラスに、削除された、またはアクセスできないデストラクタを持つメンバーがある場合、合成された既定のコンストラクタは削除済みとして定義されます。または、クラス内初期化子を持たない参照メンバーがあります。または、既定のコンストラクターを明示的に定義しない型の const メンバーがあり、そのメンバーにはクラス内初期化子がありません。

これらのルールがここで 2 番目のエラーをどのように説明しているかわかりません。

class Foo {
public:
  Foo(int i) { }
};

class Bar {
private:
  Foo foo;
};

int main() {
  Foo foo; //error: no matching constructor in Foo
  Bar bar; //error: implicitly deleted constructor in Bar
  return 0;
}

最初のエラーは理解できるものであり、この質問とは直接関係ありません。2 番目のエラーは驚くべきものです。なぜなら、上記の規則では、Bar が削除済みとして合成されたデフォルト コンストラクターを取得する必要がある理由を説明していないからです。

私の本に欠けているルールは何ですか、またはルールを理解していませんか?

4

4 に答える 4

3

Fooコンストラクターを宣言するため、デフォルトのコンストラクターはありません。C++11 12.1/5 から:

クラス X に対してユーザーが宣言したコンストラクターがない場合、パラメーターを持たないコンストラクターは暗黙的にデフォルトとして宣言されます。

BarFooデフォルトのコンストラクタがないため、削除されたデフォルトのコンストラクタがあります。C++11 12.1/5 から (5 番目の箇条書き):

[...] いずれかの [...] 非静的データ メンバ [...] にデフォルト コンストラクタがない場合、クラス X のデフォルトのデフォルト コンストラクタは削除済みとして定義されます。

あなたが引用する「ルール」にはその点が欠けているようで、3番目の箇条書きで const 修飾されたメンバーの場合についてのみ言及しています。

于 2013-01-28T16:42:54.837 に答える
1

©ISO/IEC§12.1[コンストラクター]:

クラスの暗黙的に宣言されたデフォルトコンストラクタは、次のX場合に削除済みとして定義されます。

  • const修飾型(またはその配列)の非静的データメンバーには、ユーザー提供のデフォルトコンストラクターがありません。
  • 非静的データメンバーは参照型であり、
  • Xは、自明ではないデフォルトコンストラクターを持つバリアントメンバーを持つユニオンのようなクラスです。

Barデフォルトのコンストラクターがないため、インスタンス化できませんFoo(独自に定義したため、コンパイラーはデフォルトのコンストラクターを省略しました)。また、default-constructingBarを使用すると、削除されたdefault-constructorをFoo使用できなくなります。したがって、コンパイラは暗黙的にBarのコンストラクタを削除します。

これが機能する唯一の方法は、パブリックBarコンストラクターを作成Fooし、メンバーinitializer-listでオブジェクトを初期化することです。そのため、default-constructionはBarの正しいコンストラクターを呼び出しますfoo。例えば:

class Bar {
    Foo foo;
    public:
        Bar() : foo(0) {} // calls Foo::Foo(int) constructor
};

int main()
{
    Bar bar; // okay
}
于 2013-01-28T16:41:42.903 に答える
1

エラーメッセージはコンパイラに依存しますが、問題はFooがデフォルトのコンストラクタを提供しないことです。それ、そしてあなたのルールには欠けているものがあります:

標準12.1から

クラスXのデフォルトのデフォルトコンストラクタは、次の場合に削除済みとして定義されます。

直接または仮想の基本クラス、または中括弧または等しい初期化子を持たない非静的データメンバーは、クラスタイプM(またはその配列)を持ち、MにはデフォルトコンストラクターまたはMのデフォルトに適用されるオーバーロード解決(13.3)がありませんコンストラクターは、あいまいさ、またはデフォルトのデフォルトコンストラクターから削除された、またはアクセスできない関数になります。

Fooにはデフォルトのコンストラクターがないため、Barのコンストラクターは削除済みとして定義されます。

于 2013-01-28T16:42:17.323 に答える
0

おそらくのデフォルトコンストラクタは何をしますBarか? を構築する必要Fooがありますが、デフォルトで構築することはできません。Fooコンパイラーは、のコンストラクターに与える値をどのように知ることができますか? できません。したがって、いずれかのメンバーまたはベースが既定で構築できない場合、コンパイラはそのクラスの既定のコンストラクターを作成できません。したがって、標準はBarのデフォルト コンストラクタを正しく削除します。

于 2013-01-28T16:50:20.407 に答える