web-dev-qa-db-ja.com

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

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

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イディオムのコピーコンストラクターを理解しようと試みましたが、この単純な状況さえ理解していないことを発見しました。)

87
Keith

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

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

オブジェクトごとの制御のヒントがprotected access仕様に存在するため、標準(11.5)に専用の章さえあります。ただし、ここで説明されているオブジェクトごとの機能は、基本的なものです。繰り返しになりますが、C++のアクセス制御はクラスごとに機能することを意図しています。

73
AnT

「Private」は、「facebookの写真を非公開にして、見られないようにする」という意味で、実際にはアクセス制御メカニズムではありません。

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

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

28
vsekhar

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

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

次に、クラスごとのアクセス制御には、コピーコンストラクターや演算子=などの独自のユースケースがあります。アクセス制御がインスタンスごとである場合、それらを実装することは困難です。

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

12
JackyZhu

それはいくぶんarbitrary意的な言語設計の決定です。 Ruby では、privateは実際にはプライベートを意味します。たとえば、「インスタンスのみが自身のプライベートデータメンバーにアクセスできます」。ただし、これには多少制限があります。

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

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

11
André Caron

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

4
Adam Maras

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

1
Jacob