+3  A: 

$5.2.10/2 - "An expression of integral, enumeration, pointer, or pointer-to-member type can be explicitly converted to its own type; such a cast yields the value of its operand."

This means that pointers 'bs2' and 'bs3' are pointing to the same location

$9.2/16 - "Two standard-layout struct (Clause 9) types are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in declaration order) have layout-compatible types (3.9)."

This means that your class and struct are layout compatible.

$9/6-

A standard-layout class is a class that:

— has no non-static data members of type non-standard-layout class (or array of such types) or reference,

— has no virtual functions (10.3) and no virtual base classes (10.1),

— has the same access control (Clause 11) for all non-static data members,

— has no non-standard-layout base classes,

— either has no non-static data members in the most-derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and

— has no base classes of the same type as the first non-static data member.108

Since your class has a virtual destructor, your class and struct are not standard layout classes.

However you have added a 'void *' data member to possibly take care of the 'vptr' (thereby possibly mimicking layout compatibility based on your particular compiler implementation)

In this case reinterpret_cast is used to interpret the class pointer (bs2) as a struct pointer (bs3). By default struct members are public. Since the return value of reinterpret cast points to the same memory (refer quote above) where class members are located, you can modify the struct members (which are the same as the original class members).

This is cheating. This is highly discouraged.! This is most likely going to lead to undefined behavior

Chubsdad
@Chubsdad - Thank you. +1
Pavitar
The struct and the class are NOT layout-compatible: The struct has a void*, the class hasn't. And no, the vtable pointer doesn't count, as the C++ standard doesn't mandate it. Bottomline: it might work on your current compiler, but the C++ standard doesn't guarantee it.
Sjoerd
My comment and your edit must have crossed each other.
Sjoerd
@Sjoerd: Yes :), As soon as I submitted my revised update, I saw your comments.
Chubsdad
+1  A: 

But in some situations we ought to go ahead and access them.

If you have to access them in any situation, change its access specification.

Or better, make a public method that would accept a token(or some special permissions - to validate the caller), and return the requested value.

KMan
+3  A: 

But in some situations we ought to go ahead and access them.

And what, pray, are these situations?

Other than design errors, I can’t see any. Accessing private members is a no-go. If you need the access, then provide it by legal means, i.e. either make the members more accessible or use friend modifiers to access them in a controlled way.

Violating the C++ type checking system equals game over: you cheat the compiler, don’t expect it to work with you. With this kind of undefined behaviour (i.e. not just platform dependent but forbidden for good reasons) you’re just inviting trouble in the form of very hard to track bugs.

tl;dr: Don’t. Ever.

Caveat: There is one exception: you have a library that you cannot access/modify the source code of, and you have no way of influencing its interface design. And additionally you can be sure (how?) that it won’t ever change. In this case the only solution may be to hack the library with such tricks.

Konrad Rudolph
+1  A: 

What you've got there is a horrible hack around encapsulation. If you really want to access private variables then you should be using the "friend" keyword. The reason the reinterpret_cast works is because you're interpretting the bytes of class Student as the struct _Student - which has it's variables declared as public by default. There are all manner of bad ways to access the private data, here's another one I can think of:

int* bs3 = reinterpret_cast<int*>(bs2);
++bs3;
*bs3 = 5;

Just don't do it would be my advice.

Mark Ingram
+2  A: 
gilligan