Two nested classes are tied together.

Discussion in 'C++' started by Nephi Immortal, Aug 12, 2011.

  1. I create one main class. I use three data members to do addition
    between left value and right value through reference. It is the
    standard C++ code as common practice.
    Look at the code below and see my comments.

    class Data
    {
    public:
    Data() : x( 0 ), y( 0 ), z( 0 )
    {
    }

    Data( int _x, int _y, int _z ) : x( _x ), y( _y ), z( _z )
    {
    }

    ~Data()
    {
    }

    Data( const Data &rData ) : x( rData.x ), y( rData.y ), z( rData.z )
    {
    }

    Data &operator=( const Data &rData )
    {
    if( this == &rData )
    return *this;

    x = rData.x;
    y = rData.y;
    z = rData.z;

    return *this;
    }

    Data &operator+=( const Data &rData )
    {
    x += rData.x;
    y += rData.y;
    z += rData.z;

    return *this;
    }

    Data operator+( const Data &rData )
    {
    Data temp( *this );
    return ( temp += rData );
    }


    private:
    int x;
    int y;
    int z;
    };

    int main()
    {
    Data d1( 1, 2, 3 ), d2( 4, 5, 6 ), d3( 7, 8, 9 );

    d1 = d2 + d3;

    return 0;
    }


    My code looks fine. I decide to design nested classes inside main
    class. They are inner classes and are hidden from the client. The
    client uses Proxy() function to access nested class’ functions.
    I create two helper classes. Both of them are tied or related
    together. It is necessary because I put reference on data member:
    rData. The Data class remains unmodified through Proxy class’
    reference unless you never place any Object class’ data members inside
    Proxy class or they will be modified.
    I choose reference instead of copy of value because if I add more
    data members in Data class, constructor function will copy all data
    members every time it is called and destroyed. It would be overhead
    on CPU.
    I traced my code through debugger and tested all data members being
    pushed into and popped out of stack in the correct order. Everything
    is working properly.
    How can you assure that my code is NOT undefined behavior?


    class Object
    {
    private:
    class _Proxy;
    class Data
    {
    public:
    Data() : x( 0 ), y( 0 ), z( 0 )
    {
    }

    Data( int _x, int _y, int _z ) : x( _x ), y( _y ), z( _z )
    {
    }

    ~Data()
    {
    }

    Data( const Data &_rData ) : x( _rData.x ), y( _rData.y ),
    z( _rData.z )
    {
    }

    Data &operator=( const Data &_rData )
    {
    if( this == &_rData )
    return *this;

    x = _rData.x;
    y = _rData.y;
    z = _rData.z;

    return *this;
    }

    Data &operator+=( const Data &_rData )
    {
    x += _rData.x;
    y += _rData.y;
    z += _rData.z;

    return *this;
    }

    Data operator+( const _Proxy &_rProxy )
    {
    Data temp( *this );
    return ( temp += _rProxy.rData );
    }

    //private: /* Put Data class inside outer class. */
    int x;
    int y;
    int z;
    };

    Data _data;

    class _Proxy
    {
    public:
    _Proxy( Data &_data ) : rData( _data )
    {
    }

    ~_Proxy()
    {
    }

    _Proxy &operator=( const _Proxy &_rProxy )
    {
    if( this == &_rProxy )
    return *this;

    rData = _rProxy.rData;
    return *this;
    }

    _Proxy &operator=( const Data &_rData )
    {
    rData = _rData;
    return *this;
    }

    _Proxy &operator+=( const _Proxy &_rProxy )
    {
    rData += _rProxy.rData;
    return *this;
    }

    Data operator+( const _Proxy &_rProxy )
    {
    Data temp( rData );
    temp += _rProxy.rData;
    return temp;
    }

    //private: /* Put _Proxy class inside outer class. */
    Data &rData; // Reference
    };

    public:
    Object() : _data( 0, 0, 0 )
    {
    }

    Object( int _x, int _y, int _z ) : _data( _x, _y, _z )
    {
    }

    ~Object()
    {
    }

    Object( const Object &rObject ) : _data( rObject._data )
    {
    }

    Object &operator=( const Object &rObject )
    {
    if( this == &rObject )
    return *this;

    _data = rObject._data;

    return *this;
    }

    _Proxy Proxy() // _Proxy is copy of value
    {
    return _Proxy( _data ); // _data is reference
    }

    };




    int main()
    {
    Object object1, object2( 1, 2, 3 ), object3( 4, 5, 6 ), object4( 7,
    8, 9 ), object5( 10, 11, 12 );

    object1.Proxy() = object2.Proxy() + object3.Proxy() + object4.Proxy()
    + object5.Proxy();

    object2.Proxy() = object3.Proxy();
    object2.Proxy() += object4.Proxy();

    object4 = object1;

    return 0;
    }
     
    Nephi Immortal, Aug 12, 2011
    #1
    1. Advertisements

  2. Nephi Immortal

    red floyd Guest

    Is it UB, or is the code simply ill-formed?
     
    red floyd, Aug 12, 2011
    #2
    1. Advertisements

  3. “If you rename this class”

    I truly do not understand your point. What are you trying to clarify
    that you rename a class name? Please clarify. I don’t see any
    undefined behavior.

    You said Object *possibly* calls destructor function before Data and
    Proxy call destructor function. It does not make any sense. If you
    look at the stack, you will see that Data and Proxy call destructor
    function and are popped out of stack before Object calls destructor
    function.

    Try to test your code. Move Data class and Proxy class outside Object
    class. Define Data variable and Proxy variable in main function. You
    will see nothing is wrong. They are working properly as long as
    undefined behavior never occurs.

    I do not want the client to access Data class and Proxy class
    directly. They are placed inside Object class in private. The
    safeguard is sufficient maximum.

    You do not need to use counter in destructor class unless you want to
    use dynamic array.

    Please answer my question. Notice two functions in Proxy class below.

    Data operator+( const _Proxy &_rProxy )
    Proxy &operator=( const Data &_rData )

    Both Data class and Proxy class are *tied* together.

    If you design single class, the return type and function parameter
    type must be identical.
     
    Nephi Immortal, Aug 12, 2011
    #3
  4. Nephi Immortal

    red floyd Guest

    Any identifier with a leading underscore followed by an upper-case
    letter is reserved to the implementation in ANY scope. This means
    that you may not use such identifiers (like _Proxy) for your own
    purposes.

    What Paavo was saying is that outside of this issue, your code
    looks OK.
     
    red floyd, Aug 12, 2011
    #4
  5. OK. Paavo was saying is that my code is OK. What is he referring
    “OK”? I guess to be the fact as poor design. If you answer yes,
    please clarify why you think that the design is poor? Tell me more
    reasons. Perhaps, you express your opinion.

    I assume. You perhaps say do not use reference on all data members
    and always declare value type or pointer. Explain the reason. Maybe,
    reference is not the option because it leads to undefined behavior.
     
    Nephi Immortal, Aug 13, 2011
    #5
  6. You refer underscore with name is implementation. I think you refer
    an example -- _Vector_const_iterator and _Vector_iterator. The client
    can’t use either _Vector_const_iterator or _Vector_iterator. He needs
    to use vector instead because vector is inherited from
    _Vector_const_iterator and _Vector_iterator.

    I think it is ok to use these name like _Data and _Proxy because they
    are inaccessible to the client when they are protected in this parent
    class.
     
    Nephi Immortal, Aug 13, 2011
    #6
  7. Nephi Immortal

    Ian Collins Guest

    What parts of "reserved to the implementation" and "you may not use"
    weren't clear?
     
    Ian Collins, Aug 13, 2011
    #7
  8. Nephi Immortal

    red floyd Guest

    Thanks, Paavo, I didn't have my copy of the Standard available at the
    time, and I couldn't remember what it said. I just wasn't sure which
    "error" condition it was considered -- UB or ill-formed.

    Much obliged.
     
    red floyd, Aug 15, 2011
    #8
  9. Nephi Immortal

    TJorgenson Guest

    I think it is ok to use these name like _Data and _Proxy because they
    The compiler is allow to create a macro with these names as well.
    Macros can't be scoped.
     
    TJorgenson, Aug 16, 2011
    #9
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.