Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!cs.utexas.edu!usc!brutus.cs.uiuc.edu!apple!amdahl!pacbell!osc!strick From: strick@osc.COM (henry strickland) Newsgroups: comp.lang.c++ Subject: Re: Chameleon objects (calling virtual functions from constructors) Keywords: virtual functions, constructor functions Message-ID: <1727@osc.COM> Date: 11 Dec 89 20:57:03 GMT References: <11266@csli.Stanford.EDU> <47479d37.12160@espol> Reply-To: strick@osc.com (henry strickland) Organization: Object-Sciences Corporation (1-800-9-OBJECT) Lines: 89 In article <47479d37.12160@espol> roger@procase.UUCP (Roger H. Scott) writes: > >[Digression #2 - for Language Lawyers only] >"Derived *(*)()" [pointer to function returning pointer to Derived] >should be type compatible with "Base *(*)()" [pointer to function >returning pointer to Base]. These types were compatible in 1.2. In 1.2 you did get away with this, because there were no multiply inherited bases buried within an object -- all the bases overlaid each other, starting at the same address. I don't think this is for Language Lawyers only -- all 2.0 users need to understand [it took me a while to realize it, and I'm still finding cases where I had missed one of the aftershocks of it] that all pointers (of different pointer-to-base-class types) to an object do *not* necessarily contain the same absolute value. The following program demonstrates a simple example where (Base*)&x and (Derived*)&x are not the same absolute value, for a Derived x. ============================================== strick@gwarn /tmp 445 % cat > ex.c extern "C" void printf( char const*, ... ); class Base { int b; }; class Other { int o; }; class Derived : public Other, public Base { int d; }; Derived x; main(int, char*[] ) { ::printf("%x %x\n", (Base*) &x, (Derived*) &x); return 0; } strick@gwarn /tmp 446 % CC2 ex.c CC2 ex.c: /usr/local/bin/gcc ex.c -lC2 strick@gwarn /tmp 447 % a.out 20094 20090 strick@gwarn /tmp 448 % ============================================== If you add the following lines to the end of the above code, you have a counterexample, that would be wrong if it would compile. typedef Base *(*PFPBase)(); typedef Derived *(*PFPDerived)(); Base* BaseOfX() { return &x; } void func() { PFPBase f= BaseOfX; Base* mumble= (*f)(); PFPDerived g= BaseOfX; // error: // bad initializer type Base *(*)() // for g ( PFPDerived expected) // the above would lead to the next line not // working right, if the compiler allowed // it, because fleezle would get the absolute // value (Base*)&x rather than // the absolute value (Derived*)&x . Derived* fleezle= (*g)(); } =============================================== Language Laypeople will be bit by all this on simple chains like (Base*) (void*) &x; // ERROR NOT CAUGHT BY COMPILER // (because you used casting) which could easily happen if you store the address of your x into a (void*)-collection object, then take it from the collection and cast it to a (Base*). This will NOT work with multiple inheritance. =============================================== strick@osc.com uunet!osc!strick ( formerly strick@gatech.edu )