[comp.lang.c++] inheriting constructors

soiffer@tekcrl.CRL.TEK.COM (Neil Soiffer) (01/09/89)

I could find nothing in "the book" or subsequent papers on whether
constructors are inherited by a derived type.  Normal functions are 
inherited, but in order for a constructor to be inherited, the compiler
needs to recognize that the name of the constructor has changed to be
the name of the derived class.  All of the arguments that apply to why
it is (sometimes) useful to inherit a normal function apply to why it
is (sometimes) useful to inherit a constructor.  In particular, when the
derived type merely (re)defines some virtual functions, it is annoying
(and error prone) to have to define constructors for the derived type that
are identical to the base type's constructors.

Because I could find nothing concerning the legality of inheriting
constructors, I tried some examples with cfront 1.2.1 and g++ (v 1.27?).
[Can you guess what the answer is -- you are almost certainly wrong :-)]

Below are four very simple types:
B and D (derived from B) have a single function "f" defined along with the
    constructor.
VirtualB and VirtualD (derived from VirtualB) differ from B and D in that
    their single function "vf" is a virtual function.

The main program tries to construct objects of type D, D*, virtualD, and
virtualD*.

Another behavior is demonstrated by a class hierarchy similar to "Virtual{B,D}"
called Other{B,D,DD}.  This hierarchy adds a third class adds a constructor
to OtherD and a third class OtherDD that is derived from OtherD.

Cfront allows the objects of type D and D*, but complains about constructors
for virtualD and virtualD*.  I believe that I had one example where cfront
would allow a virtualD* but not a virtualD, but I can't seem to reconstruct
that example anymore.  In the "Other" example, cfront complains
about the class definition of OtherDD "struct OtherDD  needs a constructor".
It also gives the error message
    argument  1 of type char * expected for OtherD::OtherD()

g++ complains about the constructors for all of the objects, although the
error messages differ for the malloc'd types:
test.c:51: type `VirtualD' must have constructor to take parameter list
test.c:54: structure has no method named `VirtualD'
test.c:57: type `D' must have constructor to take parameter list
test.c:60: structure has no method named `D'
g++ does not complain about the "Other" example.

I strongly feel that constructors should be inherited.  Is this question
answered anywhere?  Is there a good reason why they shouldn't be inherited?
What does cfront 2.0 do?

Below is the test program:
-----------------------------------------------
#include <stdio.h>

class B {
public:
    B(int n=5) {i=n;};
    void f() {printf("f of B\n");};
protected:
    int i;
};

class D: public B {
public:
    void f() {printf("f of D\n");};
};

class VirtualB {
public:
    VirtualB(int n=5) {i=n;};
    virtual void vf() {printf("vf of VirtualB\n");};
protected:
    int i;
};

class VirtualD: public VirtualB {
public:
    virtual void vf() {printf("vf of VirtualD\n");};
};

class OtherB {
public:
    OtherB(int n=5) {i=n;};
    virtual void vf() {printf("vf of OtherB\n");};
protected:
    int i;
};

class OtherD: public OtherB {
public:
    OtherD(char *s) {i = atoi(s);}; // this is the difference from Virtual above
    virtual void vf() {printf("vf of OtherD\n");};
};

class OtherDD: public OtherD {
public:
    virtual void vf() {printf("vf of OtherDD\n");};
};


main()
{
    VirtualD *vd_obj_ptr = new VirtualD(3);
    vd_obj_ptr->vf();

    VirtualD vd_obj = VirtualD(3);
    vd_obj.vf();

    D *d_obj_ptr = new D(3);
    d_obj_ptr->f();

    D d_obj = D(3);
    d_obj.f();
}

mat@mole-end.UUCP (Mark A Terribile) (01/10/89)

> I could find nothing in "the book" or subsequent papers on whether
> constructors are inherited by a derived type.  Normal functions are 
> inherited, but in order for a constructor to be inherited, the compiler
> needs to recognize that the name of the constructor has changed to be
> the name of the derived class.  ...

Constructors are not inherited.  ``Of course'' the base class's constructors
*are* called (See B. Stroustrup's book, section 7.2.6) and there is nothing
to prevent you from making the derived constructor(s) inline.

> 					      ...  In particular, when the
> derived type merely (re)defines some virtual functions, it is annoying
> (and error prone) to have to define constructors for the derived type that
> are identical to the base type's constructors.

If the constructors are inline and written inline, it's no longer so error
prone.

> I strongly feel that constructors should be inherited.  Is this question
> answered anywhere?  Is there a good reason why they shouldn't be inherited?

I disagree, mostly because the five or six thousand lines of C++ that I've
written (not a lot, I realize) have not shown me any real need and because
this sounds like it could be a door thrown open to errors of omission in
large classes of problems.  If you find it necessary, you might want to look
for another way to express the type relationships that you have.  With a
little more experience, I might be able to write some concrete examples; right
now I cannot.
-- 

(This man's opinions are his own.)
From mole-end				Mark Terribile

soiffer@tekcrl.CRL.TEK.COM (Neil Soiffer) (01/17/89)

I have received a few replies to my question about whether constructors
are inherited.  Most people said no (but seemed to ignore the program that
I included that showed that in cfront, they are occasionally inherited).

I have found another case where both g++ and cfront agree that the
constructors are inherited.  This case raises some questions about
c++ consistency.  In a nutshell, if
    B is a base class with a constructor "B(int)"
    D is derived from B and does not declare any new constructors,
then
    D d(5)	is allowed, but
    D d = d(5)	is not allowed.
[actually, if B has a virtual function defined on it, then cfront doesn't allow
either form and complains about the class definition of D lacking a constructor]
Unfortunately, the abbreviated form can not be used with "new" for
heap-allocated storage, so it sufficient for my purposes.

In Stroustrup's book, the only comment on the first form "D d(5)" that
I could find is on page 139, saying that the first form is an abbreviation
of the second form.  Why should an abbreviation behave differently than
the full form?

In my original message, I claimed that:
> all of the arguments that apply to why
> it is (sometimes) useful to inherit a normal function apply to why it
> is (sometimes) useful to inherit a constructor.  In particular, when the
> derived type merely (re)defines some virtual functions, it is annoying
> (and error prone) to have to define constructors for the derived type that
> are identical to the base type's constructors.

Some people said that inline functions do away with the need for inheriting
the constructors.  The same argument can be applied to any inherited function.
I don't think that this is a valid argument:  explicitly rewriting function
(headers) means you are not using inheritance.

Someone said that they had never needed this feature in their code.
Here is a real life example from the InterViews X windows library.
The class PushButton has six different constructors defined for it.
It has a (inherited) virtual function "Press" that is called when the button
is pressed (actually, when it is released).  A simple way to get a specific
desired behavior for a PushButton is to create a new class "MyPushButton"
and redefine the virtual function "Press" to do what you want.
The *only* new behavior this class introduces is for the Press function.
Why should "MyPushButton" have to (re)introduce the six constructors that
are defined for "PushButton".

At the C++ conference this fall, it was mentioned that a "complete" language
description was supposed to be floating around among some of the "inside"
parties this spring.  Does this reference manual exist in some preliminary
form and if so, does it discuss whether constructors are inherited in a
correct implementation of c++?

For completeness, an example showing the "maybe" nature of inheriting
constructors is shown below.  I tried this example on cfront 1.2.1 and
on g++ (v 1.27?).

	Neil Soiffer
	Textronix Computer Research Lab
	ARPA:  soiffer@CRL.TEK.COM
	UUCP:  ...!tektronix!tekchips!soiffer

-----------------
#include <stdio.h>

class B {
public:
    B(int n) {i=n;};
    void f() {printf("f of B\n");};
protected:
    int i;
};

class D: public B {
public:
    void f() {printf("f of D\n");};
};


class VirtualB {
// cfront won't accept this class def without a constructor
// difference from class B above is that the function is a virtual function.
public:
    VirtualB(int n) {i=n;};
    virtual void vf() {printf("vf of VirtualB\n");};
protected:
    int i;
};

class VirtualD: public VirtualB {
public:
    virtual void vf() {printf("vf of VirtualD\n");};
};


main()
{
    D d_obj(3);					// works for both
    d_obj.f();

    VirtualD vd_obj(3);				// works for g++, not cfront
    vd_obj.vf();

    D d_obj2 = D(3);				// works for cfront, not g++
    d_obj2.f();

    VirtualD vd_obj2 = VirtualD(3);		// doesn't work for either
    vd_obj2.vf();
}

turner@sdti.SDTI.COM (Prescott K. Turner) (01/27/89)

In article <3477@tekcrl.CRL.TEK.COM>, soiffer@tekcrl.CRL.TEK.COM (Neil Soiffer) says:
> [...] the program that I included that showed that in cfront, they
> [constructors] are occasionally inherited
What cfront does with your example seems very odd.  I've heard it said
so often that constructors are not inherited that I can't point out
when Dr. Stroustrup said it.  This non-inheritance is intentional.  What's
more, you are looking not just for constructors to be inherited, but
to be accessible by the name of the derived class.  Such a feature is not
described in the book or in any of the other papers describing the
definition of C++.

> In Stroustrup's book, the only comment on the first form "D d(5)" that
> I could find is on page 139, saying that the first form is an abbreviation
> of the second form.  Why should an abbreviation behave differently than
> the full form?
Indeed cfront treats them identically in the sample program you present.
It's g++ which handles them differently, and it's a bug.

> The *only* new behavior this class introduces is for the Press function.
> Why should "MyPushButton" have to (re)introduce the six constructors that
> are defined for "PushButton".
Yes, good example.

> Does this reference manual exist in some preliminary
> form and if so, does it discuss whether constructors are inherited in a
> correct implementation of c++?
Yes, where I work we are lucky to be among the reviewers of the revised
reference manual for C++.  It is not finished, so reviewing it has its
price as well as benefits.  I can't comment on what it says about
inheritance of constructors, but if it is silent we will mention that in
our review.
--
Prescott K. Turner, Jr.
Software Development Technologies, Inc.
375 Dutton Rd., Sudbury, MA 01776 USA        (508) 443-5779
UUCP: ...{harvard,mit-eddie}!sdti!turner    Internet: turner@sdti.sdti.com