阻止程序员使用任何技巧来访问私有类成员

时间:2015-08-09 10:43:46

标签: c++

通过声明成员私有,非好友函数无法直接访问该成员。但是有一种方法可以通过使用指针的类型转换来访问它们,例如:

class Foo {

  private:
    int value;

  public:
    inline int get() {
      return value;
    }
    inline Foo (int value) {
      Foo::value = value;
    }

} foo(1234);

int main() {
  using namespace std;
  cout << foo.display() << endl; // display 1234
  int *p = (int *)(&foo); // HERE!
  *p = 5678;
  cout << foo.display() << endl; // display 5678, foo.value has been changed
  return 0;
}

我们可以阻止用户使用这些技巧吗?或者我们可以禁止将Foo *转换为int *吗?

3 个答案:

答案 0 :(得分:4)

嗯,不,不可能阻止确定的程序员进行显式类型转换,因为确定的程序员可以使用几乎无限的方式 - 特别是如果愿意接受潜在的未定义行为。

哲学上,C ++类型系统通常旨在使事故更难以做事。但是,它并不是为了防止程序员故意破坏类型系统。

通过使用技术组合可能会使事情变得更加困难;

  1. 使用pimpl成语(已经在parapura rajkumar的回答中提到)
  2. 向成员(包括pimpl)引入偏移量。例如,对于程序员来说,实现细节可能会偏移18个字节,这不一定是显而易见的。
  3. 为您的班级提供私人operator&(),这会阻止使用&object获取对象的地址。
  4. 不提供返回this的成员函数,也不返回任何私有或受保护类数据的地址(或引用)。并且没有公开数据。
  5. 然而,事实上,一个足够坚定的程序员会找到一种方法来处理各种各样的技巧,即使没有访问源代码也是如此。这些技巧也会带来令人遗憾的结果,让开发人员更难以以更常见的方式使用你的课程。

答案 1 :(得分:2)

一种选择是使用PIMPL惯用法,并且永远不要将实现类标题包含在库中。

class A
{
    Aimpl* a_;
public:
    int getValue();
};

现在用户可以访问但永远不会知道Aimpl的内部修改它。

答案 2 :(得分:0)

您无法阻止任何人在您展示时编写看似有效且正常工作的代码。

貌似因为

 *p = 5678;

实际上是未定义的行为,不能依赖于给出与您相同的结果。