[comp.lang.c++] Pulling back the covers...

dmg@ssc-vax.UUCP (David Geary) (05/27/89)

  Well, thanks to all who answered my question on _vptr's and how to get
.c files output with Glockenspiel.
  For me, the best way to learn C++ is to write some "simple" C++ programs,
and examine the C output they produce.  For example, I was wondering how
inheritance "works", so I did the following:

// From test.cxx:

class base
{
  int   baseone;
  float basetwo;
};

class derived : base
{
  double  derivedone;
  char    derivedtwo;
};

main() {}

...  Ok, so it doesn't do much when run ;-), but here's the .c file:

/* from test.c, produced by:  ccxx @c test.cxx (with Glockenspiel) */

/* << cfxx :-  1.2 Apollo.0 >> */
/* < listtest.cxx */
void *_new(); void _delete(); void *_vec_new(); void _vec_delete();
void exit();

struct base {	/* sizeof base == 8 */

int _base_baseone ;
float _base_basetwo ;
};

struct derived {	/* sizeof derived == 18 */

int _base_baseone ;
float _base_basetwo ;

double _derived_derivedone ;
char _derived_derivedtwo ;
};

int main (){  _entry (); { }
 exit ( 0 ); }

/* the end */

  
  Of course for you hard-core C++ers, this is probably nothing too revealing.
But for me, this simple test gives me the insight to understand *why* I
can treat a pointer to derived as though it were a pointer to base, which
makes me a much better C++ programmer than if I just knew that I *could*
treat a pointer to derived as though it were a pointer to base.

  It's interesting to note that in Brad Cox's book, "Object Oriented
Programming:  An Evolutionary Approach", he states that MI under
Objective C is "possible", while MI under C++ is "impossible".
  After looking at the above code, we realize that:

main()
{
  base mybase;
  derived myderived;

  mybase.baseone    = 9;
  myderived.baseone = 10;
}

(the above) works because both base and derived structs have all the
members of base at the beginning of the struct:

 &mybase  -----------------     &derived  -----------------------
          | _base_baseone |               | _base_baseone       |
          | _base_basetwo |               | _base_basetwo       |
          -----------------               | _derived_derivedone |
                                          -----------------------

  Therefore, offsets into both structs are the same when accessing
"baseone" (really _base_baseone).

  All of this does make one ponder, however, how MI can be implemented.
Obviously, this scheme for single inheritance cannot be extrapolated
for MI.  If class derived multiply inherited from base and, say,
class Object, how can one treat a derived as though it were *both*
a base and an Object.  Obviously, the offsets into the struct will
be mangled, because we can't put all members of both base and
Object at the beginning of a derived.  Therefore, I probably would
also conclude, that MI under C++ is "impossible", under the
present scheme used to work single inheritance. 

  Anyone care to shed some light on how MI is implemented under
C++?  My guess would be that the scheme for inheritance must be
reworked, and that possibly, if a class multiply inherits, that
an extra pointer must be included in the struct definition for
the class.





-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ David Geary, Boeing Aerospace, Seattle                 ~ 
~ "I wish I lived where it *only* rains 364 days a year" ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~