Re: Type conversion function for user type again.
On May 18, 3:03 am, zaemi...@gmail.com 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:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34