[comp.lang.c++] calling non-default constructors

asc@concurrent.co.uk (Andy Chittenden) (01/24/90)

// The following program demonstrates a problem with virtual inheritence:

class base {
  public:
    base();
    base(unsigned long& p);
};


class derived : public virtual base {
  public:
    derived();
    derived(unsigned long& p);
};

derived::derived(unsigned long& p) : base(p) {}


class mostderived : public virtual derived {
  public:
    mostderived();
    mostderived(unsigned long& p);
};

mostderived::mostderived(unsigned long& p) : derived(p) {}

main()
{
	unsigned long counter;
	mostderived x(counter);
}

// The problem encountered is that without virtual inheritence the
// constructor for mostderived with parameter p does call derived's
// constructor with parameter p and derived's constructor with parameter p
// does call upon base's constructor with parameter.  This is exactly how
// you would expect it to work.  However, with virtual inheritence, it
// doesn't work like this at all.  In order to prevent the constructor for
// base being called twice when used with multiple inheritence,
// mostderived's constructor with parameter p calls upon base's constructor
// WITHOUT parameter p.  This means that the base part of mostderived is
// not constructed properly.  The code generated is ( with much
// editting):

// struct mostderived *__ct__11mostderivedFRUl (__0this , 
// __0base , __0derived , __0p )
// struct mostderived *__0this ;
// struct base *__0base ;
// struct derived *__0derived ;
// unsigned long *__0p ;

// #line 25 "0708067014.C"
// { if (__0this || 
// (__0this = (struct mostderived *)__nw__FUi (sizeof(struct mostderived))))
// ( (__0this -> Pbase= ((__0base == 0 )?( (__0base =
// #line 25 "0708067014.C"
// (((struct base *)((((char *)__0this ))+ 12)))), 
//->>>>>> __ct__4baseFv ( ((struct base *)((((char *)__0this ))+ 12))) )
// :__0base )), (__0this -> Pderived= ((__0derived ==
// #line 25 "0708067014.C"
// 0 )?( (__0derived = (((struct derived *)((((char *)__0this ))+ 8)))), 
// __ct__7derivedFRUl ( ((struct derived *)((((char *)__0this ))+ 8)), 
// __0base , __0p ) )
// #line 25 "0708067014.C"
// :__0derived ))) ;
// 
// #line 25 "0708067014.C"
// return __0this ;
// }

// The line marked with ->>>>>> is the line that calls upon base's no
// parameter constructor.

// One way around this is to implement the constructor differently as:

// mostderived::mostderived(unsigned long& p) : derived(p), base(p) {}

// However, this presents a problem with regard to impact of change.  If
// I now split base into two for some reason:
//
// class mostbase {
//  public:
//    mostbase();
//    mostbase(unsigned long& p);
// };

// and
// class base : public virtual mostbase {
// ....
// };
//
// I would now need to change the implementation of mostderived
// constructor to:

// mostderived::mostderived(unsigned long& p) : derived(p), 
//				base(p),
//				mostbase(p) {}

// I would also need to change derived's constructor as well.

// This seems to go against the object-oriented principle of keeping
// the impact of a change to the class being changed if the interface
// remains the same.

// Cfront could have generated pointers to pointers in the above code
// to prevent base being constructed with the "wrong" constructor.  In
// other words (in simplified pseudo C++):

// mostderived::mostderived(mostderived* this, base** x, derived** y,
//		unsigned long& p)

// { if (this != NULL || this = new mostderived) {
//     *y = (*y == NULL) ? derived::derived((char*) this + 8, x, p)
//		: *y ; 
//     *x = (*x == NULL) ? base::base((char*) this + 12) : *x;
//			/* the constructor on this line won't get 
//			called if derived's constructor
//			runs base's constructor */
//     this->Pbase = *x;
//     this->Pderived = *y;
//     return this;
// }

// (Aside: the above code is identical to the AT&T generated code up
// above except that the parameters to the routines are pointers to
// pointers rather than pointers - obviously the *y and *x
// expressions would be y and x respectively in AT&T's generated code.
// This should help your understanding of some AT&T's generated code!).

// Any comments?, Andy