同じクラスのオブジェクトがお互いのプライベートデータにアクセスするのはなぜですか?


98

同じクラスのオブジェクトがお互いのプライベートデータにアクセスするのはなぜですか?

class TrivialClass {
public: 
  TrivialClass(const std::string& data) :
    mData(data) {};

  const std::string& getData(const TrivialClass& rhs) const {
    return rhs.mData;
  };

private:
  std::string mData;
};

int main() {
  TrivialClass a("fish");
  TrivialClass b("heads");

  std::cout << "b via a = " << a.getData(b) << std::endl;
  return 0;
}

このコードは機能します。オブジェクトaがオブジェクトbのプライベートデータにアクセスして返すことは完全に可能です。なぜそうなのでしょうか?個人データは個人のものだと思います。(私はpimplイディオムのコピーコンストラクターを理解することから始めましたが、この単純な状況さえ理解していないことがわかりました。)


18
まあ、出発点として、最も単純なクラス以外のコピーコンストラクターを適切に実装することはできません。クラスは自分の親友であると考えることができます:-)
Cameron

4
顧客から非公開であると考えてください。ただし、クラスのすべての従業員はアクセスできます
Martin Beckett

キャメロン、ありがとう。それは理にかなっていますが、このアクセスがコピーコンストラクタと代入演算子のみに制限されていないのはなぜですか。
キース、

5
同じタイプのオブジェクトは、多くの場合相互作用します。また、別のインスタンスのプライベートデータを渡すメソッドを作成するように強制する人はいません。:)
UncleBens 2011

4
コンパイル時に、コンパイラーが同じオブジェクトを識別する方法がないためです。このようなアクセスを実施するには、実行時のサポートが必要です。
チェサン2013年

回答:


80

それがC ++での動作方法だからです。C ++では、アクセス制御はクラスごとに機能しますオブジェクトごとではなく、ごとに機能します。

C ++のアクセス制御は、静的なコンパイル時機能として実装されます。コンパイル時に意味のあるオブジェクトごとのアクセス制御を実装することは実際には不可能であることは明らかです。この方法で実装できるのは、クラスごとのコントロールのみです。

オブジェクトごとの制御のいくつかのヒントは、保護されたアクセス仕様にあります。そのため、標準(11.5)に専用の章があります。しかし、そこに記述されているオブジェクトごとの機能はまだ初歩的なものです。繰り返しになりますが、C ++のアクセス制御はクラスごとに機能することを意図しています。


9
+1。C ++はコンパイル時のメカニズムに大きく影響しますが、実行時のメカニズムにはそれほど影響しません。かなり良い原則。
ニモ

4
あなたの「コンパイル時に意味のあるオブジェクトごとのアクセス制御を実装することは実際には不可能です」。何故なの?void X::f(X&x)コンパイラは区別やすい可能であるthis->ax.a。(常に)コンパイラがそれを知っていて*thisxそれx.f(x)が呼び出されても実際には同じオブジェクトであるとは限りませんが、言語設計者がこれで問題ないことを確認できます。
アンドレ・キャノン

@AndréCaron私はこれは実際には魚のやかんのはるかに大きいと思います。インライン化が行われない場合、コンパイラーは常にthis、および&xが同じかどうかのチェックを行う必要があります。さらに悪いことに、これは実際にはでも問題になりX::f(Y& y)ます。具体的なオブジェクトはZXとの両方から継承するタイプになる可能性があるためYです。要するに、MIで賢く動作させるのは、パフォーマンスではなく、実際の混乱です。
Nir Friedman

@NirFriedman私はあなたが提案を誤解していると思います。のコンパイル時にX::f(X& x)、へのアクセスがあった場合、コンパイルされx.aません。他に何も変更せず、チェックを挿入する必要がないため、まだ有効なプログラムのパフォーマンスに影響を与えません。また、既存のC ++への重大な変更としては提案されていませんが、設計者がprivate最初に導入したときに行うことができるものとして提案されています。
Alexey Romanov

31

「プライベート」は、「Facebookで自分の写真を非公開にして、表示されないようにする」という意味で、実際にはアクセス制御メカニズムではありません。

C ++では、「プライベート」とは、これらがクラスの一部であり、クラスのコーダーが将来のバージョンなどで変更する可能性があることを示し、クラスを使用する他のコーダーがその存在や機能に依存することを望まない。

真のアクセス制御が必要な場合は、本物のデータセキュリティ技術を実装する必要があります。


13

これは良い質問で、最近この質問に遭遇しました。私は同僚といくつかの議論をしました、そしてここに私たちの議論の要約があります:これは設計によるものです。この設計がすべての場合に完全に合理的であるという意味ではありませんが、クラスごとにプライベートが選択される理由がいくつかあるはずです。私たちが考えることができる考えられる理由は次のとおりです。

まず第一に、インスタンスごとのアクセス制御のコストは非常に高くなる可能性があります。これはこのスレッドで他の人によって議論されています。理論的には、これはこのポインターチェックを。ただし、これはコンパイル時に行うことはできず、実行時にのみ行うことができます。したがって、実行時に各メンバーのアクセス制御を特定する必要があります。違反すると、例外のみが発生する可能性があります。コストが高い。

次に、クラスごとのアクセス制御には、コピーコンストラクターや演算子=などの独自の使用例があります。インスタンスごとにアクセス制御を行うと、実装が困難になります。

さらに、アクセス制御は、データではなくコード/メンバーへのアクセスをモジュール化/制御する方法について、主にプログラミング/言語の観点から行われます。


12

これは、恣意的な言語設計の決定です。ではルビー、例えば、private「独自のプライベートデータメンバにアクセスすることができる唯一のインスタンス」のように、本当に、プライベートを意味します。ただし、これには制限があります。

コメントで指摘されているように、コピーコンストラクターと代入演算子は、別のインスタンスのプライベートデータメンバーに直接アクセスする一般的な場所です。その理由はそれほど明確ではありません。

次のケースを考えてみましょう。OOリンクリストを実装しています。リンクリストには、ポインタを管理するためのネストされたノードクラスがあります。このノードクラスを実装して、ポインタ自体を管理することができます(ポインタをパブリックにしてリストで管理するのではなく)。このような場合、典型的なコピーコンストラクターと代入演算子が存在する他の場所で、他のノードオブジェクトのポインターを変更するノードオブジェクトが必要になります。


4

トリックは、データがあることを覚えておくことがあるprivate、クラスではなく、インスタンスのクラスの。クラス内のすべてのメソッドは、そのクラスの任意のインスタンスのプライベートデータにアクセスできます。他のインスタンスのプライベートデータメンバーに明示的にアクセスするメソッドを禁止しない限り、インスタンス内でデータをプライベートに保つ方法はありません。


1

上記のすべての回答に加えて、カスタムコピーコンストラクター、代入演算子、および他のインスタンスで動作するクラスに対して作成する他のすべての関数を検討してください。これらすべてのデータメンバーに対してアクセサ関数が必要になります。


-8

プライベートデータは、そのデータにアクセスできる誰かが他の人に公開するまで、プライベートのままです。

この概念は、次のような他の状況にも適用されます。

class cMyClass
{
public:
   // ...
   // omitted for clarity
   // ...

   void Withdraw(int iAmount)
   {
      iTheSecretVault -= iAmount;
   }

private:
   int iTheSecretVault;
};

どうすれば誰でもお金を引き出すことができますか?:)


3
この例では、1つのクラスインスタンスが別のインスタンスのプライベートデータメンバーにアクセスすることはありません。
アンドレ・キャノン

@Andre、「この概念は他の状況にも適用されます...など」
YeenFei

^ "その他の状況"は定義から外れているので、あなたの例は関連性がありません(そして、それが他のどこかで有益であることはわかりません)
underscore_d

1
これは質問に対する正しい説明ではありません。
Panda
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.