davidm@uunet.UU.NET (David S. Masterson) (04/25/91)
>>>>> On 25 Apr 91 06:35:47 GMT, [I] said:
Me> #ifdef GPLUSPLUS
Me> #include <stream.h>
Me> #else
Me> #include <iostream.h>
Me> #include <iomanip.h>
Me> #endif
Me> class alpha { // top of the hierarchy
Me> int value1;
Me> public:
Me> alpha(int a) : value1(a) {}
Me> virtual void display() {
Me> cout << "Alpha value1 " << value1 << "\n";
Me> }
Me> };
Me> class beta : public alpha { // middle of the hierarchy
Me> int value2;
Me> public:
Me> beta(int a, int b) : alpha(a), value2(b) {}
Me> virtual void display() {
Me> alpha::display();
Me> cout << "Beta value2 " << value2 << "\n";
Me> }
Me> };
Me> class gamma : public beta { // bottom of the hierarchy
Me> int value3;
Me> public:
Me> gamma(int a, int b, int c) : beta(a, b), value3(c) {}
Me> virtual void display() {
Me> beta::display();
Me> cout << "Gamma value3 " << value3 << "\n";
Me> }
Me> };
Me> void testfunc(alpha*& parm) {
Me> cout << "testfunc display\n";
Me> parm = new alpha(40);
Me> parm->display();
Me> }
Me> int main() {
Me> gamma g(10, 20, 30);
Me> cout << "first display\n";
Me> g.display();
Me> cout << "second display\n";
Me> gamma *gptr = &g;
Me> gptr->display();
Me> testfunc((alpha*) gptr);
// ^-- why is the cast necessary?
Me> cout << "third display\n";
Me> gptr->display();
Me> }
Me> // End of the program
I don't understand why the cast is necessary. Without the cast, Oregon C++,
Turbo C++, and G++ tells me something like:
Warning: Lvalue coerced into temporary to initialize reference type
Can anyone explain why?
--
====================================================================
David Masterson Consilium, Inc.
(415) 691-6311 640 Clyde Ct.
uunet!cimshop!davidm Mtn. View, CA 94043
====================================================================
"If someone thinks they know what I said, then I didn't say it!"
wmm@world.std.com (William M Miller) (04/29/91)
cimshop!davidm@uunet.UU.NET (David S. Masterson) writes: > [long example deleted] > I don't understand why the cast is necessary. Without the cast, Oregon C++, > Turbo C++, and G++ tells me something like: > > Warning: Lvalue coerced into temporary to initialize reference type > > Can anyone explain why? The deleted example essentially boils down to something like: class Base { }; class Derived: public Base { }; void f(Base*&); void g() { Derived* p = new Derived; f((Base*) p); } This question comes up fairly regularly. To paraphrase E&S section 4.7, you can convert an X& to a Y& without a cast if and only if Y is an unambiguous accessible base class of X. In this example, Base stands in that relationship to Derived, but Base* and Derived* do not -- pointers are not classes! This distinction is of more than academic concern. Consider the following slightly-elaborated example (using structs to allow access while keeping the line count down): struct Base1 { int i; }; struct Base2 { }; struct Derived: Base1, Base2 { }; Base2 b2; void f(Base2*& b2p) { b2p = &b2; } int main() { Derived* dp; g(dp); // Illegal -- for example purposes only dp->i = 5; } If you run this program, you will scribble on the memory immediately preceding the "b2" object in static storage. I hope this example illustrates why a Derived* is not compatible with a Base*&. The message you are getting is the same one you get if you try to do something like int i; double* dr = i; The value of "i" will be converted into a double and the reference will be initialized with that temporary, not with "i". In the original example, the Derived* was converted into a Base* and the reference argument initialized with the resulting temporary. That's why the current (2.1/E&S) definition only allows such an initialization if the reference is const (i.e., const X&) and the target consequently cannot be modified. -- William M. Miller, Glockenspiel, Ltd. wmm@world.std.com
rae@alias.com (Reid Ellis) (04/30/91)
text in []'s omitted for brevity's sake. David S. Masterson <cimshop!davidm@uunet.UU.NET> writes: |class alpha { [..] }; |class beta : public alpha { [..] }; |class gamma : public beta { [..] }; | |void testfunc(alpha*& parm) { [..] | parm = new alpha(40); [..] |} | |int main() { | gamma g(10, 20, 30); [..] | gamma *gptr = &g; [..] | testfunc((alpha*) gptr); | // ^-- why is the cast necessary? [..] |} | |I don't understand why the cast is necessary. This has to do with the fact that when you cast from a derived class to a base class, the value of the pointer can change. This has been the case since multiple inheritance came into being in C++ [and quite possibly, since before then]. In the above program, when you cast "gamma *gptr" to an "alpha*", the value of gptr may be changed to point to its "alpha part". This pointer is then passed in to testfunc(). testfunc(), which takes a reference to said pointer can now set it to point at anything that may or may not be a "gamma". Now in main() when you return from the call to testfunc(), C++ will have no idea what to do with gptr. Should it offset it back to where it was, relative to the [new] value of its "alpha" pointer? Basically, you're trying to rip out the guts of a gamma. :) As long as a gamma* has the same pointer value as its respective alpha*, your cast will work. But if, say you were to do something like this: class beta : public something, public alpha { .. }; then your cast would no longer be valid.. Reid -- Reid Ellis 1 Trefan Street Apt. E, Toronto ON, M5A 3A9 rae@utcs.toronto.edu || rae@alias.com CDA0610@applelink.apple.com || +1 416 362 9181 [work]