Internals of an object

Discussion in 'C++' started by ma740988, Sep 12, 2004.

  1. ma740988

    ma740988 Guest

    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.
     
    ma740988, Sep 12, 2004
    #1
    1. Advertising

  2. ma740988

    David Hilsee Guest

    "ma740988" <> wrote in message
    news:...
    > 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.

    --
    David Hilsee
     
    David Hilsee, Sep 12, 2004
    #2
    1. Advertising

  3. "ma740988" <> skrev i en meddelelse
    news:...
    > 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
     
    Peter Koch Larsen, Sep 12, 2004
    #3
  4. ma740988

    Old Wolf Guest

    (ma740988) wrote:
    > 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?
     
    Old Wolf, Sep 12, 2004
    #4
  5. ma740988

    ma740988 Guest

    (Old Wolf) wrote in message news:<>...
    [...]
    >
    > 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.
    >

    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?
     
    ma740988, Sep 13, 2004
    #5
  6. Re: Re: Internals of an object

    Old Wolf <> wrote:
    > > 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.


    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.
     
    Sektor van Skijlen, Sep 14, 2004
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jobs Gooogle
    Replies:
    2
    Views:
    482
    Patricia Shanahan
    May 11, 2007
  2. Jobs Gooogle
    Replies:
    1
    Views:
    322
    Victor Bazarov
    May 10, 2007
  3. Jobs Gooogle

    .Net VC++ Java C++ Windows Internals Unix Internals

    Jobs Gooogle, May 10, 2007, in forum: C Programming
    Replies:
    0
    Views:
    362
    Jobs Gooogle
    May 10, 2007
  4. Replies:
    0
    Views:
    274
  5. Jobs Gooogle
    Replies:
    0
    Views:
    127
    Jobs Gooogle
    May 10, 2007
Loading...

Share This Page