web-dev-qa-db-ja.com

コピーコンストラクターでプライベート変数にアクセスできるのはなぜですか?

クラス内のget関数でのみ、プライベート変数にアクセスできないことを学びました。しかし、なぜコピーコンストラクタでアクセスできますか?

例:

Field::Field(const Field& f)
{
  pFirst = new T[f.capacity()];

  pLast = pFirst + (f.pLast - f.pFirst);
  pEnd  = pFirst + (f.pEnd - f.pFirst);
  std::copy(f.pFirst, f.pLast, pFirst);
}

私の宣言:

private:
  T *pFirst,*pLast,*pEnd;
76
demonking

私見、既存の答えは、これの「なぜ」を説明する悪い仕事をします-どんな振る舞いが有効であるかを繰り返すことに集中しすぎています。 「アクセス修飾子はクラスレベルで機能し、オブジェクトレベルでは機能しません。」 - そうだね。でも何で?

ここで最も重要な概念は、クラスを設計、作成、保守するプログラマーがOOカプセル化を望み、実装を調整する権限を与えられることを期待されていることです。 _class X_を記述している場合、個々の_X x_オブジェクトを、アクセス可能なコードで使用する方法だけでなく、次のようにエンコードします。

  • 派生クラスは、(オプションで純粋な仮想関数および/または保護されたアクセスを通じて)それと対話することができます。
  • distinct Xオブジェクトcooperateデザインの事後条件と不変条件を尊重しながら、意図した動作を提供します。

それは単なるコピーコンストラクターでもありません-非常に多くの操作がクラスの2つ以上のインスタンスを含むことができます:比較、追加/乗算/除算、コピー構築、クローン作成、割り当てなどをしている場合、それは多くの場合です単純に他のオブジェクトのプライベートデータや保護データにアクセスする必要があるか、よりシンプルで高速な、または一般的に優れた機能の実装を許可する必要があります。

具体的には、これらの操作は特権アクセスを利用して次のようなことをしたい場合があります。

  • (コピーコンストラクタ)イニシャライザリストで「rhs」(右側)オブジェクトのプライベートメンバーを使用します。これにより、メンバー変数自体が、デフォルトで構築される(正当な場合でも)のではなく、コピーで構築されてから(再び、合法的な場合)
  • リソースの共有-ファイルハンドル、共有メモリセグメント、データを参照する_shared_ptr_ s.
  • 物事の所有権を取る、例えば_auto_ptr<>_は、構築中のオブジェクトの所有権を「移動」します
  • ゼロから再生成することなく、最適に使用可能な状態で新しいオブジェクトを構築するために必要なプライベート「キャッシュ」、キャリブレーション、または状態メンバーをコピーします
  • コピーされているオブジェクトに保持されている診断/トレース情報をコピー/アクセスします。パブリックAPIを介してアクセスすることはできませんが、後の例外オブジェクトまたはロギングで使用される可能性があります(たとえば、「元の」非コピー構築インスタンスの時間/状況建設された)
  • 一部のデータのより効率的なコピーを実行します。オブジェクトには、たとえば_unordered_map_メンバーですが、begin()およびend()イテレータのみを公開します-size()への直接アクセスにより、reserve容量を高速化できますコピー; at()insert()のみを公開し、それ以外の場合はthrow....
  • クライアントコードに対して不明または書き込み専用である可能性がある親/調整/管理オブジェクトに参照をコピーします。
28
Tony Delroy

アクセス修飾子はクラスレベルで機能し、オブジェクトレベルでは機能しません。

つまり、同じクラスの2つのオブジェクトが互いにプライベートデータにアクセスできます。

なぜ:

主に効率のためです。 this == otherにアクセスするたびにother.xかどうかをチェックすることは、無視できない実行時オーバーヘッドになります。

スコープの観点から考えると、意味論的にも論理的です。「プライベート変数を変更するとき、コードのどの部分を念頭に置く必要がありますか?」 –クラス全体のコードを念頭に置く必要があります。これは、実行時に存在するオブジェクトとは直交します。

また、コピーコンストラクターと代入演算子を記述するときに非常に便利です。

104
aioobe

別のインスタンスのメンバーであっても、クラス内からクラスのプライベートメンバーにアクセスできます。

33

答えを理解するために、いくつかの概念を思い出したいと思います。

  1. 作成するオブジェクトの数に関係なく、そのクラスのメモリには1つの関数のコピーが1つしかありません。これは、関数が一度だけ作成されることを意味します。ただし、変数はクラスのインスタンスごとに異なります。
  2. thisポインターは、呼び出されるとすべての関数に渡されます。

これは、thisポインターが原因で、関数はその特定のインスタンスの変数を見つけることができます。プライベートかパブリックかは関係ありません。その関数内でアクセスできます。ここで、同じクラスの別のオブジェクトにポインターを渡すと。この2番目のポインターを使用して、プライベートメンバーにアクセスできます。

これがあなたの質問に答えることを願っています。

11
Ali Zaib

コピーコンストラクターはクラスのメンバー関数であるため、「プライベート」として宣言されたものであっても、クラスのデータメンバーにアクセスできます。

6
Bojan Komazec