为什么同一类的对象可以访问彼此的私有数据?

时间:2011-08-03 03:00:34

标签: c++ private-members

为什么同一类的对象可以访问彼此的私有数据?

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习语中的复制构造函数,但后来我发现我甚至不理解这种简单的情况。)

7 个答案:

答案 0 :(得分:71)

因为它是如何在C ++中工作的。在C ++中,访问控制基于每个类,而不是基于每个对象。

C ++中的访问控制是作为静态编译时功能实现的。我认为很明显,在编译时实际上不可能实现任何有意义的每对象访问控制。只有每类控制才能实现。

受保护访问规范中存在一些每对象控件的提示,这就是为什么它甚至在标准中有自己的专用章节(11.5)。但是,那里描述的任何每个对象的特征仍然相当简陋。同样,C ++中的访问控制意味着按类进行操作。

答案 1 :(得分:27)

“私人”实际上不是一个访问控制机制,意思是“我在Facebook上将我的照片设为私有,因此您无法看到它们。”

在C ++中,“私有”只是说这些是你(类的编码员)在未来版本中可能会改变的类的一部分,等等,你不希望其他编码人员使用你的类来依赖他们的存在或功能。

如果您想要真正的访问控制,您应该实施真正的数据安全技术。

答案 2 :(得分:12)

这是一个很好的问题,我最近遇到过这个问题。我与同事们进行了一些讨论,以下是我们讨论的总结: 这是设计的。这并不意味着这种设计对于所有情况都是完全合理的,但必须考虑为什么选择每个类私有。我们可以想到的可能原因包括:

首先,每个实例访问控制的成本可能非常高。这个帖子中的其他人已经讨论过这个问题。理论上,这可以通过 this 指针检查来完成。但是,这不能在编译时完成,并且只能在运行时完成。因此,您必须在运行时识别每个成员的访问控制,并且当它被违反时,可能只会引发异常。成本很高。

其次,每个类访问控制都有自己的用例,比如copy constructor或operator =。如果每个实例都有访问控制,那么很难实现它们。

另外,访问控制主要来自编程/语言,如何模块化/控制对代码/成员的访问,而不是数据。

答案 3 :(得分:10)

这有点像任意语言设计决定。例如,在Ruby中,private实际上意味着私有,因为“只有实例才能访问其自己的私有数据成员”。但是,这有点限制。

正如评论中所指出的,复制构造函数和赋值运算符是您直接访问另一个实例的私有数据成员的常见位置。原因不太明显。

考虑以下情况。您正在实施OO链接列表。链表有一个用于管理指针的嵌套节点类。您可以实现此节点类,以便它自己管理指针(而不是将指针公开并由列表管理)。在这种情况下,您希望节点对象想要在典型的复制构造函数和赋值运算符的其他位置修改其他节点对象的指针。

答案 4 :(得分:4)

诀窍是要记住数据是private,而不是类的实例。类中的任何方法都可以访问该类的任何实例的私有数据;除非您禁止显式访问其他实例的私有数据成员的方法,否则无法在实例中保持数据私有。

答案 5 :(得分:1)

除了上面的所有答案之外,还可以考虑自定义复制构造函数,赋值运算符以及为其他实例操作的类编写的所有其他函数。您需要所有这些数据成员的访问者功能。

答案 6 :(得分:-7)

私人数据保持私密状态,直到有权访问它的人将其显示给其他人。

这个概念也适用于其他情况,例如:

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

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

private:
   int iTheSecretVault;
};

怎么可能有人取钱? :)