Type conversion function for user type again.

Discussion in 'C++' started by zaeminkr@gmail.com, May 18, 2007.

  1. Guest

    I got a good answer here I have still confusing part.

    I have two very simple classes

    class DRect
    {
    private :
    double x0, y0, x1, y1;
    public :
    DRect(double a, double b, double c, double d) : x0(a), y0(b),
    x1(c), y1(d) {}
    void Union(const DRect* p)
    {
    x0 = MIN(x0, p->x0);
    y0 = MIN(y0, p->y0);
    x1 = MAX(x1, p->x1);
    y1 = MAX(y1, p->y1);
    }
    };

    class IRect
    {
    private :
    int x0, y0, x1, y1;
    public :
    IRect(int a, int b, int c, int d) : x0(a), y0(b), x1(c), y1(d)
    {}
    operator DRect() const
    {
    return DRect(x0, y0, x1, y1);
    }
    operator DRect*() const
    {
    return &DRect(x0, y0, x1, y1);
    }
    };

    and the execution code here.

    void main()
    {
    DRect d(5.3, 5.3, 15.6, 15.6);
    IRect i(10, 10, 100, 100);

    /* 1. No problem with compiling this code. */
    d.Union(&(static_cast<DRect>(i)));

    /* 2. It isn't compiled. */
    d.Union(&i);
    }

    My question is

    1. The second execution code 'd.Union(&i)' is quite resonable. People
    usually do something like this.

    DRect d1(2.3, 5.3, 98.2, 34.2);
    DRect d2(5.2, 4.2, 99.1, 54.9);

    d1.Union(&d2);

    So I want people can do something like this also.

    DRect d1(2.3, 5.3, 98.2, 34.2);
    IRect i(5, 4, 99, 54);

    d1.Union(&i);

    However, the compiler is only accept
    'd.Union(&(static_cast<DRect>(i)));' form. My 'operator' functions are
    wrong?

    2. Where is the temporary object exist? stack?

    operator DRect() const
    {
    return DRect(x0, y0, x1, y1);
    }
    operator DRect*() const
    {
    return &DRect(x0, y0, x1, y1);
    }

    If the temporary DRect object is exist on stack, it's still exist
    when the 'DRect::Union' is executed?


    Thanks.
    , May 18, 2007
    #1
    1. Advertising

  2. Guest

    On May 17, 6:03 pm, wrote:
    > I got a good answer here I have still confusing part.
    >
    > I have two very simple classes
    >
    > class DRect
    > {
    > private :
    > double x0, y0, x1, y1;
    > public :
    > DRect(double a, double b, double c, double d) : x0(a), y0(b),
    > x1(c), y1(d) {}
    > void Union(const DRect* p)
    > {
    > x0 = MIN(x0, p->x0);
    > y0 = MIN(y0, p->y0);
    > x1 = MAX(x1, p->x1);
    > y1 = MAX(y1, p->y1);
    > }
    >
    > };
    >
    > class IRect
    > {
    > private :
    > int x0, y0, x1, y1;
    > public :
    > IRect(int a, int b, int c, int d) : x0(a), y0(b), x1(c), y1(d)
    > {}
    > operator DRect() const
    > {
    > return DRect(x0, y0, x1, y1);
    > }
    > operator DRect*() const
    > {
    > return &DRect(x0, y0, x1, y1);
    > }
    >
    > };
    >
    > and the execution code here.
    >
    > void main()
    > {
    > DRect d(5.3, 5.3, 15.6, 15.6);
    > IRect i(10, 10, 100, 100);
    >
    > /* 1. No problem with compiling this code. */
    > d.Union(&(static_cast<DRect>(i)));
    >
    > /* 2. It isn't compiled. */
    > d.Union(&i);
    >
    > }
    >
    > My question is
    >
    > 1. The second execution code 'd.Union(&i)' is quite resonable. People
    > usually do something like this.
    >
    > DRect d1(2.3, 5.3, 98.2, 34.2);
    > DRect d2(5.2, 4.2, 99.1, 54.9);
    >
    > d1.Union(&d2);
    >
    > So I want people can do something like this also.
    >
    > DRect d1(2.3, 5.3, 98.2, 34.2);
    > IRect i(5, 4, 99, 54);
    >
    > d1.Union(&i);

    The auto type conversion conforms to C++ standard. You can refer to
    some materials. The conversion only happens in some special situation.
    The compiler cannot find all the potential conversion for you.
    >
    > However, the compiler is only accept
    > 'd.Union(&(static_cast<DRect>(i)));' form. My 'operator' functions are
    > wrong?
    >
    > 2. Where is the temporary object exist? stack?
    >
    > operator DRect() const
    > {
    > return DRect(x0, y0, x1, y1);
    > }
    > operator DRect*() const
    > {
    > return &DRect(x0, y0, x1, y1);
    > }
    >
    > If the temporary DRect object is exist on stack, it's still exist
    > when the 'DRect::Union' is executed?

    No! when the DRect function return, the temporary obj on stack will be
    callbacked.
    >
    > Thanks.
    , May 18, 2007
    #2
    1. Advertising

  3. On 18 Maj, 03:03, wrote:
    > I got a good answer here I have still confusing part.
    >
    > I have two very simple classes
    >
    > class DRect
    > {
    > private :
    > double x0, y0, x1, y1;
    > public :
    > DRect(double a, double b, double c, double d) : x0(a), y0(b),
    > x1(c), y1(d) {}
    > void Union(const DRect* p)
    > {
    > x0 = MIN(x0, p->x0);
    > y0 = MIN(y0, p->y0);
    > x1 = MAX(x1, p->x1);
    > y1 = MAX(y1, p->y1);
    > }
    >
    > };
    >
    > class IRect
    > {
    > private :
    > int x0, y0, x1, y1;
    > public :
    > IRect(int a, int b, int c, int d) : x0(a), y0(b), x1(c), y1(d)
    > {}
    > operator DRect() const
    > {
    > return DRect(x0, y0, x1, y1);
    > }
    > operator DRect*() const
    > {
    > return &DRect(x0, y0, x1, y1);
    > }
    >
    > };
    >
    > and the execution code here.
    >
    > void main()
    > {
    > DRect d(5.3, 5.3, 15.6, 15.6);
    > IRect i(10, 10, 100, 100);
    >
    > /* 1. No problem with compiling this code. */
    > d.Union(&(static_cast<DRect>(i)));
    >
    > /* 2. It isn't compiled. */
    > d.Union(&i);
    >
    > }


    Use references instead, pointers should normally not be used unless
    you have to.

    #include <iostream>

    class DRect {
    private :
    double x0, y0, x1, y1;
    public :
    DRect(double a, double b, double c, double d)
    : x0(a), y0(b), x1(c), y1(d) {}

    void Union(const DRect& p) {
    std::cout << "Union";
    }
    };

    class IRect {
    private :
    int x0, y0, x1, y1;
    public :
    IRect(int a, int b, int c, int d)
    : x0(a), y0(b), x1(c), y1(d) {}

    operator DRect() const {
    return DRect(x0, y0, x1, y1);
    }
    };

    int main() { // Notice int and not void as return-type
    DRect d(5.3, 5.3, 15.6, 15.6);
    IRect i(10, 10, 100, 100);
    d.Union(i);
    }

    --
    Erik Wikström
    =?iso-8859-1?q?Erik_Wikstr=F6m?=, May 18, 2007
    #3
  4. James Kanze Guest

    On May 18, 3:03 am, wrote:
    > I got a good answer here I have still confusing part.
    >
    > I have two very simple classes


    > class DRect
    > {
    > private :
    > double x0, y0, x1, y1;
    > public :
    > DRect(double a, double b, double c, double d) : x0(a), y0(b),
    > x1(c), y1(d) {}
    > void Union(const DRect* p)
    > {
    > x0 = MIN(x0, p->x0);
    > y0 = MIN(y0, p->y0);
    > x1 = MAX(x1, p->x1);
    > y1 = MAX(y1, p->y1);
    > }
    > };


    > class IRect
    > {
    > private :
    > int x0, y0, x1, y1;
    > public :
    > IRect(int a, int b, int c, int d) : x0(a), y0(b), x1(c), y1(d)
    > {}
    > operator DRect() const
    > {
    > return DRect(x0, y0, x1, y1);
    > }
    > operator DRect*() const
    > {
    > return &DRect(x0, y0, x1, y1);
    > }
    > };


    > and the execution code here.


    > void main()


    Just a nit, but technically, this shouldn't compile. According
    to the language specification, main() must return an int.

    > {
    > DRect d(5.3, 5.3, 15.6, 15.6);
    > IRect i(10, 10, 100, 100);


    > /* 1. No problem with compiling this code. */
    > d.Union(&(static_cast<DRect>(i)));


    Really? It shouldn't compile---the result of the static cast
    here is an rvalue, and you cannot take the address of an rvalue.

    > /* 2. It isn't compiled. */
    > d.Union(&i);
    > }


    > My question is


    > 1. The second execution code 'd.Union(&i)' is quite resonable.


    Not really. DRect and IRect are two classes unrelated by
    inheritance. The fact that you can convert one of them to the
    other doesn't mean that you can implicitly convert a pointer to
    one to a pointer to the other. The relationship here is roughly
    the same as that between int and double: an int converts
    explicitly to a double, but an int* doesn't convert to a
    double*.

    The reason for this is, of course, obvious. If you have an int,
    take it's address, and try to access it as a double, you're
    going to get into deep trouble, very fast.

    > People usually do something like this.


    > DRect d1(2.3, 5.3, 98.2, 34.2);
    > DRect d2(5.2, 4.2, 99.1, 54.9);


    > d1.Union(&d2);


    > So I want people can do something like this also.


    > DRect d1(2.3, 5.3, 98.2, 34.2);
    > IRect i(5, 4, 99, 54);


    > d1.Union(&i);


    Why the pointers? This looks like a case where references would
    be more appropriate. The langage does allow using an rvalue (a
    temporary) to initialize a reference to const.

    This might even be a case where inheritance would be
    appropriate. I don't know that actual application, but it seems
    like you are saying that a user should be able to use an IRect
    as a DRect; that is typically what inheritance is about. (On
    the other hand, inheritance and assignment don't work very well
    together, so if your class has value semantics, you might prefer
    keeping the implicit conversions rather than using inheritance.)

    > However, the compiler is only accept
    > 'd.Union(&(static_cast<DRect>(i)));' form. My 'operator' functions are
    > wrong?


    Curiously enough, g++ only gives a warning here, even with
    -std=c++98 -pedantic. Even more surprising, VC++ doesn't even
    warn, unless you use /Za (in which case, it is an error). This,
    despite the fact that it has never been legal, and that even the
    earliest C compilers treated it as an error (so compatibility
    with existing code cannot be the reason). It is, at any rate,
    definitly illegal, and always has been. (Sun CC rejects it, and
    as far as I know, doesn't have an option to allow it.)

    > 2. Where is the temporary object exist? stack?


    Where ever the compiler wants to put it. With a couple of
    restrictions, however: the resulting code must be reentrant, and
    (I think) the compiler may not generate a call to the global
    operator new.

    In practice, it will be in the same memory space where the
    compiler puts local variables---on a machine with a stack,
    almost certainly on the stack.

    > operator DRect() const
    > {
    > return DRect(x0, y0, x1, y1);
    > }
    > operator DRect*() const
    > {
    > return &DRect(x0, y0, x1, y1);
    > }


    > If the temporary DRect object is exist on stack, it's still exist
    > when the 'DRect::Union' is executed?


    It exists until the end of the full expression in which it is
    constructed. Since the full expression in your case includes
    the call to DRect::Union, it will exist during this call. (You
    would get into trouble, however, if DRect::Union saved the
    pointer somewhere, and used it in a later function.)

    Note that while there are different conventions with regards to
    when to use references, and when to use pointers, every
    convention I've ever heard of would use references in your case:
    you don't accept null pointers, you don't modify the referenced
    object, and you don't store the pointer for later use, after the
    end of the function. And you want to be able to call the
    function using temporaries (resulting from arbitrary
    expressions or implicit type conversions).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 18, 2007
    #4
  5. Guest

    On May 18, 3:27 pm, wrote:
    > On May 17, 6:03 pm, wrote:
    >
    >
    >
    > > I got a good answer here I have still confusing part.

    >
    > > I have two very simple classes

    >
    > > class DRect
    > > {
    > > private :
    > > double x0, y0, x1, y1;
    > > public :
    > > DRect(double a, double b, double c, double d) : x0(a), y0(b),
    > > x1(c), y1(d) {}
    > > void Union(const DRect* p)
    > > {
    > > x0 = MIN(x0, p->x0);
    > > y0 = MIN(y0, p->y0);
    > > x1 = MAX(x1, p->x1);
    > > y1 = MAX(y1, p->y1);
    > > }

    >
    > > };

    >
    > > class IRect
    > > {
    > > private :
    > > int x0, y0, x1, y1;
    > > public :
    > > IRect(int a, int b, int c, int d) : x0(a), y0(b), x1(c), y1(d)
    > > {}
    > > operator DRect() const
    > > {
    > > return DRect(x0, y0, x1, y1);
    > > }
    > > operator DRect*() const
    > > {
    > > return &DRect(x0, y0, x1, y1);
    > > }

    >
    > > };

    >
    > > and the execution code here.

    >
    > > void main()
    > > {
    > > DRect d(5.3, 5.3, 15.6, 15.6);
    > > IRect i(10, 10, 100, 100);

    >
    > > /* 1. No problem with compiling this code. */
    > > d.Union(&(static_cast<DRect>(i)));

    >
    > > /* 2. It isn't compiled. */
    > > d.Union(&i);

    >
    > > }

    >
    > > My question is

    >
    > > 1. The second execution code 'd.Union(&i)' is quite resonable. People
    > > usually do something like this.

    >
    > > DRect d1(2.3, 5.3, 98.2, 34.2);
    > > DRect d2(5.2, 4.2, 99.1, 54.9);

    >
    > > d1.Union(&d2);

    >
    > > So I want people can do something like this also.

    >
    > > DRect d1(2.3, 5.3, 98.2, 34.2);
    > > IRect i(5, 4, 99, 54);

    >
    > > d1.Union(&i);

    >
    > The auto type conversion conforms to C++ standard. You can refer to
    > some materials. The conversion only happens in some special situation.
    > The compiler cannot find all the potential conversion for you.


    My opinion is different. Compiler knows "DRect::Union(const DRect*)"
    function so when it meets 'd.Union(&i)', it knows that the type of 'i'
    should be 'DRect' type. However it realizes 'i' is 'IRect' type and
    tries to covert them into 'DRect' type.

    There are some possible conversions.

    1. Convert 'i'(DRect type) into 'const DRect' type and do address
    operator(&). It makes 'i' to 'const DRect*' type.
    => needs 'IRect::eek:perator DRect()'

    2. Convert '&i'(DRect* type) into 'const DRect*' type.
    => needs 'IRect::eek:perator DRect*()'

    I still don't know why compiler doesn't do this.

    >
    >
    >
    >
    >
    > > However, the compiler is only accept
    > > 'd.Union(&(static_cast<DRect>(i)));' form. My 'operator' functions are
    > > wrong?

    >
    > > 2. Where is the temporary object exist? stack?

    >
    > > operator DRect() const
    > > {
    > > return DRect(x0, y0, x1, y1);
    > > }
    > > operator DRect*() const
    > > {
    > > return &DRect(x0, y0, x1, y1);
    > > }

    >
    > > If the temporary DRect object is exist on stack, it's still exist
    > > when the 'DRect::Union' is executed?

    >
    > No! when the DRect function return, the temporary obj on stack will be
    > callbacked.
    >


    No, I don't think so. I do some more with compiler to understand this.

    1. When the execution exists in 'main', the 'ESP' and call stack is
    like this.

    --------------------------------------------
    ESP = 0012FEC4

    main(int 1, char * * 0x003711c0) line 49
    mainCRTStartup() line 206 + 25 bytes
    KERNEL32! 7c816fd7()
    --------------------------------------------

    2. When the execution exists in 'operator DRect', the 'ESP' and call
    stack is like this.

    --------------------------------------------
    ESP = 0012FE68

    IRect::eek:perator DRect() line 36
    main(int 1, char * * 0x003711c0) line 53 + 12 bytes
    mainCRTStartup() line 206 + 25 bytes
    KERNEL32! 7c816fd7()
    --------------------------------------------

    3. Finally, when the execution exists in 'DRect::Union', the 'ESP' and
    call stack is like this.

    --------------------------------------------
    ESP = 0012FE48

    DRect::Union(const DRect * 0x0012ff30) line 17
    main(int 1, char * * 0x003711c0) line 58
    mainCRTStartup() line 206 + 25 bytes
    KERNEL32! 7c816fd7()
    --------------------------------------------

    As you can see, the address of the 'DRect::Union's argument('const
    DRect*') is '0x0012ff30'.
    It's below 'ESP = 0x0012FE48' which means the temporary DRect instance
    is still safe in stack when the execution exists in
    'DRect::Union'(Stack grows downward.).

    Actually the memory for temporary DRect instance was allocated in
    stack when the execution get into 'main' function

    The above code, the local var's address is this.

    d(local DRect instance) : 0x0012ff60
    i(local IRect instance) : 0x0012ff50

    *the temporary DRect instance from the type conversion : 0x0012ff30.

    Am I right? That's what I understood from debugging.

    >
    >
    >
    >
    > > Thanks.- Hide quoted text -

    >
    > - Show quoted text -- Hide quoted text -
    >
    > - Show quoted text -- Hide quoted text -
    >
    > - Show quoted text -
    , May 18, 2007
    #5
    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. amit
    Replies:
    0
    Views:
    381
  2. che
    Replies:
    2
    Views:
    483
  3. abcd

    Importing again and again

    abcd, Jun 8, 2006, in forum: Python
    Replies:
    9
    Views:
    318
    Maric Michaud
    Jun 9, 2006
  4. Replies:
    1
    Views:
    443
    Sylvester Hesp
    May 16, 2007
  5. Shannon
    Replies:
    10
    Views:
    1,025
    Jonathan Bromley
    Oct 22, 2010
Loading...

Share This Page