1
#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.
}

Does not this break a class's encapsulation? I'm a beginner of c++. I have never seen this method that can access to a class's private member in the book "c++ primer".

binbin
  • 93
  • 4

2 Answers2

2

This is allowed because A is a standard_layout class, which is a class that is compatible with the layout of other languages, meaning it can be passed to functions that have been written in something other than C++. It breaks encapsulation but this isn't something you generally want to do in C++ land, it's a compatibility feature.

Since you're a beginner however, you almost certainly want to avoid doing anything that involves using c-style casts / reinterpret_cast. Trust the type system and access controls, they're there to help you - if you override them you'll need to know exactly why, which obviously wasn't the case here.

user657267
  • 20,568
  • 5
  • 58
  • 77
  • 1
    Thanks for the clarification to my now deleted wrong answer, I certainly learned something today. However, with `virtual` all bets are off. – vsoftco Apr 06 '15 at 04:18
1

Your code is essentially undefined behavior. By the following lines:

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

you are dereferencing a type-punned pointer, despite the fact that such type-punning does not respect the strict aliasing rules. For a correct version of your code, A should be an aggregate type, see Type aliasing section here. In your code, A is practically not an aggregate type, since it contains a private member. See the definition of an aggregate type here.

Lingxi
  • 14,579
  • 2
  • 37
  • 93
  • Alternatively, `a.value` and `*p` are both the same type (`int`), so the strict aliasing rules are being respected. – Ben Voigt Apr 06 '15 at 05:03
  • Concerning the 4th bullet point, `A` is required to be an aggregate type. But it is not. The fact that `a.value` and `*p` are of the same type `int` does not change anything. See the 5th comment to the accepted answer in http://stackoverflow.com/questions/29298508/strict-aliasing-rule-in-c11/. – Lingxi Apr 06 '15 at 05:06
  • Sorry for the confusing comments earlier. The strict aliasing rule doesn't apply here. From [class.mem] / 20 we learn that `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.`, i.e. the compiler has to assume the address can refer to an `int` as well as an `A`. – user657267 Apr 07 '15 at 00:23
  • @user657267 Pointers of different types addressing the same location. This is called type-punning and is exactly when strict aliasing rules apply. – Lingxi Apr 07 '15 at 01:11
  • @Lingxi Except in this case where an exception is specifically given in the standard. If the above code violated strict aliasing it would make the entire concept of a standard-layout class pointless to define. – user657267 Apr 07 '15 at 02:16