www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Constructor inheritance & polish function

reply Kristian <kjkilpi gmail.com> writes:
Let there be classes Base and Derived. Base is the base class of Derived=
.

There are several constructors in Base. Derived can have constructors as=

follows:

1) Derived has only the default constructor which calls 'Base.this()' if=

it exists.
2) Derived uses the same constructor interface as Base. The constructors=

are not modified in any way (i.e. they simply call the ones in Base).
3) Derived uses the same constructor interface as Base. Some or all of t=
he
constructers are modified.
4) Derived uses different constructor interface as Base.

To my experience the commonness of the situations is: 2, 3, 4, and 1.


So constructors should be inherited from the base class. For example:

class Base {
      this() {...}
      this(int val) {...}

      void f() {...}
}

class Derived : Base {
      void f() {...}  //overrule a member function
}

void func() {
      Derived obj =3D new Derived(1);  //calls 'Base.this(int)' (now a c=
ompile
time error)
}

It would make the case 2 breeze to implement!

If you define constructors for Derived, then the ones defined in Base
should be hidden. The case 1 could be achieved by defining one
constructor: 'this() {}'.


If there was a polish function (just like one in Qt) which is called aft=
er
a constructor is finished, it would save unnecessary constructor writing=

in some cases. It would be especially useful when Derived is using the
same constructor interface as Base (case 2) except the constructors shou=
ld
do something additional also (subtype of case 3). For example:

class Base {
      this() {
          m_val =3D -1;
          }
      this(int val) {
          m_val =3D val;
          }

      void f() {
          m_val =3D 100;
          }

      int m_val;
}

class Derived : Base {
      this_polish() {  //is called after a constructor
          f();
          }
}

void func() {
      Derived obj =3D new Derived(1);  //'obj.m_val' =3D=3D 100 (first 1=
, then  =

100)
}


This would reduce redundant code, which is a possible source for typos a=
nd
errors. It would also be easier to maintain: if parameter lists of Base'=
s
constructors are modified, no changes will be required for Derived.
Aug 21 2006
parent Kristian <kjkilpi gmail.com> writes:
I forgot to mention that this would not break the old code.

I can't think any reason why this is not implemented in D (or in C++).  =

Maybe someone could enlighten me on this? Surely it'll make subclassing =
 =

easier and more bug free. The overload function hiding rule does not app=
ly  =

here. That is, changing the constructors of Base won't break the  =

constructors of Derived (because they just call the ones of Base).

If someone would prefer a (little) better example, here's a one:

class Button {
     this(...) {...}
     this(...) {...}
     //and zillion other constructors...

     void paint() {...}  //paints the button on the screen
}

Now we'll need a button that paints a cross over the button in some  =

situations:

class MyButton : Button {
     void paint() {
         super.paint();

         if(m_is_crossed) {
             //paint the cross
             ...
         }
     }

     bool m_is_crossed =3D false;
}

No need to rewrite (copy&paste + modify) those zillion constructors of  =

Button.

If a more complex initialization should be done (i.e. in addition of "bo=
ol  =

m_is_crossed =3D false;"), then the polish function would be candy.


On Mon, 21 Aug 2006 10:39:31 +0300, Kristian <kjkilpi gmail.com> wrote:
 Let there be classes Base and Derived. Base is the base class of Deriv=

[snip]
 class Base {
       this() {...}
       this(int val) {...}

       void f() {...}
 }

 class Derived : Base {
       void f() {...}  //overrule a member function
 }

 void func() {
       Derived obj =3D new Derived(1);  //calls 'Base.this(int)' (now a=

 compile
 time error)
 }

 class Derived : Base {
       this_polish() {  //is called after a constructor
           f();
           }
 }

 void func() {
       Derived obj =3D new Derived(1);  //'obj.m_val' =3D=3D 100 (first=

 100)
 }


 This would reduce redundant code, which is a possible source for typos=

 and
 errors. It would also be easier to maintain: if parameter lists of Bas=

 constructors are modified, no changes will be required for Derived.

Aug 21 2006