10

私はちょうどこのコードを使用して参照を試しています:

class A
{
};

class B
{
public:
    B(A& a): m_a(a){}

    A& m_a;
};

int main()
{
    A a;
    B b(a);
    B b1 = b;
}

どちらもB b1 = b;エラーになると思っていました。代わりに、VS2008 でコンパイルすると、警告が表示されます

警告 C4512: 'B': 代入演算子を生成できませんでした

この警告が表示される理由を理解しています。B b1 = b;しかし、コンパイラもステートメントに対してエラーを生成するべきではありませんか? コピーコンストラクターを生成したが、代入演算子を生成しなかったようなものです。この 2 つは本質的に互いにリンクしていませんか? もう一方が生成できなかったときに、そのうちの 1 つだけのデフォルト実装を生成することは理にかなっていますか?

4

5 に答える 5

11
warning C4512: 'B' : assignment operator could not be generated

質問 1: なぜこの警告が表示されるのですか?
参照は、作成時に一度だけ初期化できます。Reference は作成された型変数の単なるエイリアスであり、引き続きそのままであるため、作成後に別の同じ型変数への参照を再割り当てすることはできません。再割り当てしようとすると、エラーが発生します。
通常、コンパイラはデフォルトですべてのクラスに暗黙的なビットごとの代入演算子を生成しますが、この場合class Bはメンバーとして参照があるm_aため、コンパイラが暗黙的な代入演算子を生成すると、参照を再代入できないという基本的なルールが破られます。そのため、コンパイラはこの警告を生成して、暗黙的な代入演算子を生成できなかったことを通知します。

質問 2: しかし、コンパイラは B b1 = b; に対してエラーを生成するべきではありません。発言も?
生成された警告とこの特定の操作はまったく関係がありません。
B b1 = b;暗黙的な(@AndreyTによって正しく指摘されているように)コピーコンストラクターを呼び出しますB::B(const B&)。暗黙のコピー コンストラクターは、クラスが既定で生成するメンバー関数の 1 つです。したがって、警告やエラーはありません。

質問 3: コピー コンストラクターは生成されましたが、代入演算子は生成されなかったようです。この 2 つは本質的に互いにリンクしていませんか?
いいえ、まったく関係ありません。はい、コンパイラはコピー コンストラクタを生成しましたが、上記の質問 1 の回答で指定された理由により、代入演算子を生成できませんでした。これは、メンバー参照m_aがコンストラクター自体の本体で初期化される可能性があるためです。の場合のような割り当てではなく、作成時の初期割り当てです=

質問 4: 他の実装を生成できなかったときに、そのうちの 1 つのみの既定の実装を生成することは理にかなっていますか?
3つの質問への回答はこれに答えるようです。

コード例で実行されている操作を繰り返します。

B b(a);変換コピー コンストラクターB::B(A&)
B b1 = b;を呼び出す デフォルトのコピー コンストラクターを呼び出すB::B(const B&)

追加のシナリオを検討してください。
あなたがそれを持っB b1 = a;ていれば、それが呼び出されるB::B(A&)ので、再びエラーは発生しません。

B::B(A&)ただし、が宣言されexplicitている場合、コンパイラはエラーをマークimplicit conversionsし、conversion function.

ここで同じことを確認してください。

于 2011-05-25T06:18:50.147 に答える
4

C++ 言語のコンストラクターは初期化を実行し、代入演算子は代入を実行します。初期化と代入はまったく異なる概念です。

C++ 言語の参照は初期化できるため、コンパイラは、参照を持つクラスの暗黙的なコピー コンストラクターを問題なく生成できます。このB b1 = b;ステートメントは、暗黙的に生成されたコピー コンストラクターを使用します。エラーが発生すると予想する理由がわかりません。

ただし、参照自体を割り当てる (再割り当てする) ことはできません。そのため、コンパイラは、参照を持つクラスに対して暗黙的なコピー代入演算子を生成することを拒否します。コンパイラは、警告を発行してそのことを通知しました。実際にBプログラムでクラスの代入演算子を使用しようとすると、エラーが発生します。

この点で、参照の状況はメンバーの状況とほぼ同じconstです。あるクラスにconstメンバーがある場合、コンパイラーはこのクラスの暗黙のコピー コンストラクターを問題なく生成しますが、暗黙の代入の生成を拒否します。

于 2011-05-25T16:52:39.573 に答える
1

サンプルには代入演算子は必要ありません。VC ++は、必要に応じて生成できないことを警告しているだけです。これは、ライブラリを作成していて、ライブラリのユーザーがBをコピーする必要があるかもしれないと予測するのを忘れた場合に役立つ情報です。

警告が必要ない場合は、警告を抑制するか(たとえば、#pragmaを使用して)、プライベート代入演算子を宣言して実装しないことができます。その後、誰かが代入演算子を呼び出そうとすると、リンク時エラーで失敗します。

于 2011-05-25T17:29:23.313 に答える
1

参照は 1 回だけ初期化でき、変更することはできません。コンストラクターは m_a を初期化するため有効ですが、コピーによって m_a が再割り当てされますが、これは禁止されています。

于 2011-05-25T06:13:42.050 に答える
0

B b(a);は有効なステートメントです。B::B(A&)type のオブジェクトをAのコンストラクターに渡すと、 が呼び出されるためですB

ちなみにg++ではおっしゃる通り警告は出ません。(そして私見、デフォルトのコピーコンストラクターB b1= b;が呼び出されたため、警告は表示されません。) B::B(const B&)

于 2011-05-25T06:13:21.770 に答える