【问题标题】:Why does c++ allow access to a class's private member through a pointer?为什么 c++ 允许通过指针访问类的私有成员?
【发布时间】:2015-04-06 04:03:00
【问题描述】:
#include<iostream>
using namespace std;

class A
{
    int value;
 public:
    A(){value = 1;}
    ~A(){}

    void print(){cout << value << endl;}
 };

int main()
{
    A a;
    int* p = (int*)(&a);
    *p = 20;
    a.print();//output is 20.
}

这不会破坏类的封装吗?我是 C++ 的初学者。我在《c++入门》一书中从未见过这种可以访问类的私有成员的方法。

【问题讨论】:

标签: c++ pointers encapsulation private-members


【解决方案1】:

这是允许的,因为A 是一个standard_layout 类,它是一个与其他语言的布局兼容的类,这意味着它可以传递给用非C++ 编写的函数。它打破了封装,但这不是您在 C++ 领域通常想要做的事情,它是一个兼容性特性。

但是,由于您是初学者,因此您几乎肯定希望避免做任何涉及使用 c 样式转换 /reinterpret_cast 的事情。相信类型系统和访问控制,它们会为您提供帮助 - 如果您覆盖它们,您需要确切地知道原因,这显然不是这里的情况。

【讨论】:

  • 感谢您对我现在删除的错误答案的澄清,我今天当然学到了一些东西。但是,对于virtual,所有赌注都已取消。
【解决方案2】:

您的代码本质上是未定义的行为。通过以下几行:

int* p = (int*)(&a);
*p = 20;

您正在取消引用类型双关的指针,尽管这种类型双关不遵守严格的别名规则。对于您的代码的正确版本,A 应该是一个聚合类型,请参阅 Type aliasing 部分 here。在您的代码中,A 实际上不是聚合类型,因为它包含一个私有成员。查看聚合类型的定义here

【讨论】:

  • 或者,a.value*p 都是同一类型 (int),因此严格的别名规则得到遵守。
  • 关于第 4 个要点,A 必须是聚合类型。但事实并非如此。 a.value*p 属于同一类型 int 的事实并没有改变任何东西。请参阅stackoverflow.com/questions/29298508/… 中已接受答案的第 5 条评论。
  • 抱歉之前的混乱 cmets。严格的别名规则在这里不适用。从 [class.mem] / 20 我们了解到If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member.,即编译器必须假设地址可以引用int 以及A
  • @user657267 指向同一位置的不同类型的指针。这称为类型双关语,并且恰好适用于严格的别名规则。
  • @Lingxi 除非在这种情况下,标准中明确给出了例外。如果上面的代码违反了严格的别名,那么定义标准布局类的整个概念将毫无意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-03
  • 2013-02-13
  • 1970-01-01
  • 1970-01-01
  • 2011-06-26
相关资源
最近更新 更多