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


88

クラス内の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;

コピーコンストラクターはデフォルトでクラスメンバーであるため、他のメンバーも同様です。
DumbCoder 2010年

+ 53 / -0?誰がこれに投票しましたか?他にどのようにそれらをコピーしますか?!?(非代替をデバンキングしましょう:各プライベートメンバーのパブリック参照ゲッターを作成しますか?それからそれらはまったくプライベートではありません。const&それぞれのパブリックまたは値によるゲッターを作成しますか?それからそれらは「write-private」だけです、&価値観のためにリソースを浪費し、コピーできないメンバーには失敗します。)私はそのような空虚な質問の成功に困惑し、それが何を意味するのかを完全に無視しながらコピー構築について尋ねます、そして答えはそれをデバンキングするために基本的なロジックを使用しません。彼らは乾いた技術を説明していますが、これがまばたきした質問に対するはるかに簡単な答えがあります
underscore_d

8
@underscore_d、「他にどのようにコピーしますか?」私の意見では非常に奇妙な反応です。「重力はどのように機能するのか」と答えるようなものです。「他にどうやって物事が落ちるだろう!」と クラスレベルのカプセル化とオブジェクトレベルのカプセル化を混同することは、実際には非常に一般的です。それがばかげた質問であり、答えが明白であるべきだとあなたがどのように考えるかはおかしいです。Smalltalk(おそらく典型的なオブジェクト指向言語)でのカプセル化は、実際にはオブジェクトレベルで機能することに注意してください。
aioobe 2016年

@aioobe良い点、ありがとう。私のコメントはちょっと極端です-おそらくその日コーヒーメーカーが壊れていました。この質問がなぜ人気があるのか​​、特に他の(そしておそらくそれ以上の)オブジェクト指向言語から来た人々の間で人気があるのか​​を指摘していただきありがとうございます。実際、私は主にC ++でプログラミングしている人の視点から書いていたので、私のコメントは「まばたき」されたものであったことは議論の余地があります。また、その重力のアナロジーが大好きです!
underscore_d

回答:


33

私見、既存の回答は、これの「理由」を説明するのに不十分な仕事をしています-どのような行動が有効であるかを繰り返すことに焦点を合わせすぎています。「アクセス修飾子は、オブジェクトレベルではなく、クラスレベルで機能します。」- そうだね。でも何で?

ここでの包括的な概念は、クラスを設計、作成、および保守するのはプログラマーであり、その実装を調整するために必要なOOカプセル化を理解することが期待されているということです。したがって、作成している場合はclass X、個々のX xオブジェクトにアクセスできるコードで個々のオブジェクトを使用する方法だけでなく、次の方法もエンコードします。

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

コピーコンストラクターだけではありません。非常に多くの操作で、クラスの2つ以上のインスタンスが関係する可能性があります。比較、追加/乗算/分割、コピー構築、クローン作成、割り当てなどを行う場合は、多くの場合、他のオブジェクトのプライベートデータや保護されたデータにアクセスできる必要があるか、より単純、高速、または一般的に優れた関数の実装を可能にする必要があります。

具体的には、これらの操作では、特権アクセスを利用して次のようなことを行うことができます。

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

2
最大の「理由」は、アクセス修飾子がオブジェクトレベルで機能するかどうかを確認するthis == otherために、アクセスするたびに実行時のオーバーヘッドが非常に大きくなることだと思いother.xます。
aioobe 2016

2
@aioobeあなたの答えはもっと目立つようにすべきだと思います。トニーの答えは本当に良くて概念的ですが、私が賭けをしている人なら、あなたの答えが選択の実際の歴史的理由であるに違いありません。パフォーマンスが向上するだけでなく、はるかにシンプルです。Bjarneにとって素晴らしい質問になるでしょう!
ニール・フリードマン

背景を説明しているので、私はあなたの答えに印を付けました;)
2017年

@demonking、この回答で与えられた理由は、プライベートデータを他のオブジェクトに公開することが便利である理由をカバーしていると思います。ただし、アクセス修飾子は、データを「オープンに」十分に作成することを目的としたものではありません。これらは、カプセル化のためにデータを十分に閉じることを目的としています。(利便性の観点から、公開されているプラ​​イベート変数があればさらに良いでしょう!)私は実際の理由にうまく対処すると思うセクションで答えを更新しました。
aioobe

@aioobe:古いコメントですが、とにかく...「this == otherアクセスするたびにチェックしてくださいother.x」-ポイントを逃します-other.x実行時に同等の場合にのみ受け入れられた場合this.x、そもそもポインタの書き込みother.xはそれほど多くありません。コンパイラーは、if (this == other) ...this.x...あなたがやろうとしていたことのためにあなたに書くことを強制するかもしれません。あなたの「便利さ(プライベート変数が公開されている場合はさらに)」の概念も要点を見逃しています。標準の定義方法は、適切なカプセル化を可能にするのに十分な制限がありますが、不必要に不便ではありません。
トニーデルロイ2018

108

アクセス修飾子は、オブジェクトレベルではなく、クラスレベルで機能します

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

なぜ:

主に効率によるものです。this == otherアクセスするたびにチェックすることは、無視できないランタイムオーバーヘッドになりますother.xするたびに、アクセス修飾子がオブジェクトレベルで機能ます。

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

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



10

答えを理解するために、いくつかの概念を思い出させていただきたいと思います。

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

今それは thisポインタ、関数はその特定のインスタンスの変数を見つけることができます。それが公の私的であるかどうかに関係なく。その関数内でアクセスできます。ここで、同じクラスの別のオブジェクトへのポインタを渡すと、この2番目のポインターを使用して、プライベートメンバーにアクセスできるようになります。

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


6

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


3
言語を知っている人として、私はあなたが何を意味するのか理解しています。しかし、もし私がその言語を知らなかったら、あなたはただ私に質問を繰り返しているだけだと思ったでしょう。
サンジャシント
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.