Internals of an object

M

ma740988

I sat through - what should have been a 10 minute discussion where at
issue is the 'security of a class'. Truth is I was puzzled by the
soruce, so much so that I lost track of the end result. In any event,
consider

#include <iostream>
using namespace std;

class Agent
{
private:
int iVal;
int jVal;
public:
Agent():iVal(1),jVal(2){}
void setVal(int newVal) { iVal = newVal; }
int getVali() const { return iVal; }
int getValj() const { return jVal; }
};

class MinAgent : private Agent
{
public:
int getVali() const { return Agent::getVali(); }
int getValj() const { return Agent::getValj(); }
};

int main(void)
{
MinAgent minAgent;
int *minAgentAddr = reinterpret_cast<int*>(&minAgent);

cout << "iVal=" << minAgent.getVali() << endl; // iVal=1
cout << "jVal=" << minAgent.getValj() << endl; // jVal=2

cout << "Change values:" << endl;
*minAgentAddr = -23;
*(minAgentAddr+1) = -37;

cout << "iVal=" << minAgent.getVali() << endl; //iVal=-23
cout << "jVal=" << minAgent.getValj() << endl; //jVal=-37

return 0;
}

For starters, it appears to me that the impetus behind this

int *minAgentAddr = reinterpret_cast<int*>(&minAgent);

is to fiddle with the internals of the object which puzzled me since
I'm unsure of a 'rational' reason to do such a thing and why is 'that'
even allowed?

Pictorially, I'm not following the deferencing of the 'object' and the
subsequent result. I understand the basic premise behind deferencing
pointers to change the contents of an address, but from an "object'
perspective these puzzle me.

*minAgentAddr = -23;
*(minAgentAddr+1) = -37;

So I tried to step through the source but Visual Studio didn't do me a
whole lot of justice so I thought:
minAgentAddr 'calls' function setVal which in turn sets iVal but that
makes no sense since minAgentAddr + 1 calls what? I'm confused.

Thanks in advance for your time.
 
D

David Hilsee

ma740988 said:
I sat through - what should have been a 10 minute discussion where at
issue is the 'security of a class'. Truth is I was puzzled by the
soruce, so much so that I lost track of the end result. In any event,
consider

#include <iostream>
using namespace std;

class Agent
{
private:
int iVal;
int jVal;
public:
Agent():iVal(1),jVal(2){}
void setVal(int newVal) { iVal = newVal; }
int getVali() const { return iVal; }
int getValj() const { return jVal; }
};

class MinAgent : private Agent
{
public:
int getVali() const { return Agent::getVali(); }
int getValj() const { return Agent::getValj(); }
};

int main(void)
{
MinAgent minAgent;
int *minAgentAddr = reinterpret_cast<int*>(&minAgent);

cout << "iVal=" << minAgent.getVali() << endl; // iVal=1
cout << "jVal=" << minAgent.getValj() << endl; // jVal=2

cout << "Change values:" << endl;
*minAgentAddr = -23;
*(minAgentAddr+1) = -37;

cout << "iVal=" << minAgent.getVali() << endl; //iVal=-23
cout << "jVal=" << minAgent.getValj() << endl; //jVal=-37

return 0;
}

For starters, it appears to me that the impetus behind this

int *minAgentAddr = reinterpret_cast<int*>(&minAgent);

is to fiddle with the internals of the object which puzzled me since
I'm unsure of a 'rational' reason to do such a thing and why is 'that'
even allowed?

Pictorially, I'm not following the deferencing of the 'object' and the
subsequent result. I understand the basic premise behind deferencing
pointers to change the contents of an address, but from an "object'
perspective these puzzle me.

*minAgentAddr = -23;
*(minAgentAddr+1) = -37;

So I tried to step through the source but Visual Studio didn't do me a
whole lot of justice so I thought:
minAgentAddr 'calls' function setVal which in turn sets iVal but that
makes no sense since minAgentAddr + 1 calls what? I'm confused.
<snip>

No, main never calls setVal(). The reinterpret_cast is accessing and
modifying the internals of the class via low-level (and non-portable) means.
Such code is ugly, tricky, and best avoided.

Sutter wrote a good GOTW about accessing an object's private members
(http://www.gotw.ca/gotw/076.htm). The example called "the cheat" is the
one that best resembles the code you provided.
 
P

Peter Koch Larsen

ma740988 said:
I sat through - what should have been a 10 minute discussion where at
issue is the 'security of a class'.

Security in a class is not dealt with in C++ (it is not dealt with in any
other language that i know of, for that matter). The privacy of member
variables and functions is there simply to avoid shooting yourself in the
foot.

[snip]
For starters, it appears to me that the impetus behind this

int *minAgentAddr = reinterpret_cast<int*>(&minAgent);

is to fiddle with the internals of the object which puzzled me since
I'm unsure of a 'rational' reason to do such a thing and why is 'that'
even allowed?

The purpose of reinterpret_cast is to tell the compiler that you know better
and should be used rarely if ever. One place where the is okay is where some
object somehow crosses a language barrier (e.g. call-backs in Windows).
Here, the reinterpret_cast is justified.


[snip]


/Peter
 
O

Old Wolf

class Agent
{
private:
int iVal;
int jVal;
public:
Agent():iVal(1),jVal(2){}
void setVal(int newVal) { iVal = newVal; }
int getVali() const { return iVal; }
int getValj() const { return jVal; }
};

class MinAgent : private Agent
{
public:
int getVali() const { return Agent::getVali(); }
int getValj() const { return Agent::getValj(); }
};

int main(void)
{
MinAgent minAgent;
int *minAgentAddr = reinterpret_cast<int*>(&minAgent);

Non-portable (minAgent may have different alignment requirements
to int), and undefined behaviour if it is de-referenced, because
the class may have padding before the first object.

But in the majority of cases, Agent's memory location will
consist of two ints. So &minAgent will be the same address
as &minAgent.iVal , and &minAgent + 1 will be the same
address as &minAgent.jVal. To rely on this behaviour would
be foolish, of course.
int *minAgentAddr = reinterpret_cast<int*>(&minAgent);

I'm unsure of a 'rational' reason to do such a thing and why is 'that'
even allowed?

Your question applies to reinterpret_cast in general; and the answer
is that, in some cases it is useful (especially, cases where you
have established by other means that nothing undefined is going
to happen). For example in this case, if you want to change
private data in someone else's object , and you know that on
your platform, iVal will always be at the start of the object.
Pictorially, I'm not following the deferencing of the 'object' and the
subsequent result. I understand the basic premise behind deferencing
pointers to change the contents of an address, but from an "object'
perspective these puzzle me.

*minAgentAddr = -23;
*(minAgentAddr+1) = -37;

This could be rewritten (recalling that minAgentAddr is an int *):
minAgentAddr[0] = -23;
minAgentAddr[1] = -37;

Clearer?
 
M

ma740988

[email protected] (Old Wolf) wrote in message news: said:
Non-portable (minAgent may have different alignment requirements
to int), and undefined behaviour if it is de-referenced, because
the class may have padding before the first object.

But in the majority of cases, Agent's memory location will
consist of two ints. So &minAgent will be the same address
as &minAgent.iVal , and &minAgent + 1 will be the same
address as &minAgent.jVal. To rely on this behaviour would
be foolish, of course.


Your question applies to reinterpret_cast in general; and the answer
is that, in some cases it is useful (especially, cases where you
have established by other means that nothing undefined is going
to happen). For example in this case, if you want to change
private data in someone else's object , and you know that on
your platform, iVal will always be at the start of the object.
I suspect 'always be at the start of the object' means, when viewed
from the perspective of minAgentAddr the object has been more or less
'transformed' and as such iVal and jVal are now viewed as:

Some Value Some Address
iVal - xxx 0x......
jVal - xxx 0x......
Pictorially, I'm not following the deferencing of the 'object' and the
subsequent result. I understand the basic premise behind deferencing
pointers to change the contents of an address, but from an "object'
perspective these puzzle me.

*minAgentAddr = -23;
*(minAgentAddr+1) = -37;

This could be rewritten (recalling that minAgentAddr is an int *):
minAgentAddr[0] = -23;
minAgentAddr[1] = -37;

Clearer?
 
S

Sektor van Skijlen

Your question applies to reinterpret_cast in general; and the answer
is that, in some cases it is useful (especially, cases where you
have established by other means that nothing undefined is going
to happen). For example in this case, if you want to change
private data in someone else's object , and you know that on
your platform, iVal will always be at the start of the object.

I'd let me add something, as a long C++ practicer :)))

The reinterpret_cast operator should be used ONLY and EXCLUSIVELY to cast
between char* (const char*, if another is also const) and the other type
(in both ways). The C++ standard does not exclude other uses of
reinterpret_cast, but this is the only use of reinterpret_cast, which works.
This operator is used ONLY to get access to the internal representation and
to allocate an object in memory, obtained by some "unusual" way.

One of the correct examples of use of reinterpret_cast is the definition of
std::string in gcc. This string is implemented in such a way that first there
is allocated all memory required to hold all characters of created string,
including reserved space and internal structure:

{{ refs, size } c[0] c[1] c[2] ... c[size] c[size+1] ... c[size+reserved]}

std::string has one and the only field "dat", which is of "char*" type and
points to c[0]. To get access to the private fields (of Rep private class) the
reinterpret_cast is used:

Rep* rep = reinterpret_cast<Rep*>( dat ) - 1;

This is portable, safe and correct. The reinterpret_cast operator is used
to switch between the raw "internal representation" and a "concrete" object
type. Of course, "refs" and "size" are integers.

No casts between two "concrete" type objects are correct for reinterpret_cast!


--
1 6 1 7 4 4 2 548 g4bc7a4 66z 3xt7w v1y z9p1 120 32
(( Michal "Sektor" Malecki w4 66 64 73 7564 24 5 v 34 4
)) ektor van Skijlen 1 5 5 1 844 a v r z 4
Software engineer, Motorola GSG Poland 1 2 2a 1 4
WARNING: Opinions presented by me on usenet groups are my personal opinions
ONLY and are not connected to the employer.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,999
Messages
2,570,246
Members
46,839
Latest member
MartinaBur

Latest Threads

Top