www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Order of base-class constructor calls

reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Is there any way to enforce the user to call the base-class ctor via
super(), so it's the first statement in his class ctor? e.g.:

class Base {
    this(int) { }
}

class Derived : Base {
    this(int x) {
        super(x);
        // user statements
    }
}

The problem I'm having is that Base does some required initialization
in its ctor, and Derived shouldn't be allowed to call any Base class
methods (well, virtual methods) before calling the Base ctor.

This is somewhat mitigated if I have a default constructor in the base
class, e.g.:

class Base {
    this() { /* init section */ }
    this(int) { this(); }
}

class Derived : Base {
    this(int x) {
        // Base class ctor automatically called *before* any other statements
        // user statements..
    }
}

But this is only partially safe as the user could still call super()
or super(int) after he's made some calls of his own, e.g.:

class Base {
    this() { /* init section */ }
    this(int) { this(); }
    void foo() { /* expects Base.this() having been already called */ }
}

class Derived : Base {
    this(int x) {
        foo();  // boom
        super();  // or super(int);
    }
}

So I'm looking for some techniques or tricks (or, dare I say, design
patterns :x) you guys might have if you've ever ran into this kind of
problem.
Oct 07 2011
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 07 Oct 2011 18:02:33 -0400, Andrej Mitrovic  
<andrej.mitrovich gmail.com> wrote:

 Is there any way to enforce the user to call the base-class ctor via
 super(), so it's the first statement in his class ctor? e.g.:

 class Base {
     this(int) { }
 }

 class Derived : Base {
     this(int x) {
         super(x);
         // user statements
     }
 }

 The problem I'm having is that Base does some required initialization
 in its ctor, and Derived shouldn't be allowed to call any Base class
 methods (well, virtual methods) before calling the Base ctor.

 This is somewhat mitigated if I have a default constructor in the base
 class, e.g.:

 class Base {
     this() { /* init section */ }
     this(int) { this(); }
 }

 class Derived : Base {
     this(int x) {
         // Base class ctor automatically called *before* any other  
 statements
         // user statements..
     }
 }

 But this is only partially safe as the user could still call super()
 or super(int) after he's made some calls of his own, e.g.:

 class Base {
     this() { /* init section */ }
     this(int) { this(); }
     void foo() { /* expects Base.this() having been already called */ }
 }

 class Derived : Base {
     this(int x) {
         foo();  // boom
         super();  // or super(int);
     }
 }

 So I'm looking for some techniques or tricks (or, dare I say, design
 patterns :x) you guys might have if you've ever ran into this kind of
 problem.

Maybe you can make the ctor private? Then the derived class cannot call it directly, it needs to be implicit. -Steve
Oct 11 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Nope. Private ctors have to be called from within the same module,
whether implicit or not:

test.d:
class Foo
{
    private this() { }  // Error: constructor main.Bar.this no match
for implicit super() call in constructor
}

import test;
class Bar : Foo
{
    this() { }
}

void main()
{
    auto bar = new Bar();
}
Oct 11 2011
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Fri, 07 Oct 2011 23:02:33 +0100, Andrej Mitrovic  
<andrej.mitrovich gmail.com> wrote:
 So I'm looking for some techniques or tricks (or, dare I say, design
 patterns :x) you guys might have if you've ever ran into this kind of
 problem.

The best I can come up with is a runtime solution: import std.stdio; class Base { private bool _init = false; this(int x) { _init = true; } void foo() { if (_init) writefln("ok"); else writefln("not initialised"); } } class DerivedWell : Base { this(int x) { super(x); foo(); } } class DerivedBadly : Base { this(int x) { foo(); super(x); } } void main() { auto d1 = new DerivedWell(1); auto d2 = new DerivedBadly(1); } -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Oct 11 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 11 Oct 2011 12:40:29 -0400, Andrej Mitrovic  
<andrej.mitrovich gmail.com> wrote:

 Nope. Private ctors have to be called from within the same module,
 whether implicit or not:

 test.d:
 class Foo
 {
     private this() { }  // Error: constructor main.Bar.this no match
 for implicit super() call in constructor
 }

 import test;
 class Bar : Foo
 {
     this() { }
 }

 void main()
 {
     auto bar = new Bar();
 }

Hm... that makes sense. You can try mucking around with roll-your-own construction. That is, ignore the constructor and use a mixture of public final initialize functions + protected virtual initialize functions. It might just be something that you have to accept is not definable by the base class :( C++ requires construction of base classes before the main body of a derived constructor is called. And that has its own problems too... -Steve
Oct 12 2011