www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Base Class Hitting Derived Class Invariant

reply "Vijay Nayar" <madric gmail.com> writes:
I was working on a little project when I encountered something 
odd.  Essentially a base class contains some data and a derived 
class needs a slice of that data.  Certain properties of this 
slice must be maintained, so the derived class has an invariant.

What happens is that if the base class, even in the constructor, 
calls a function that is overridden in the derived class, the 
invariant gets invoked.  This can make initialization quite 
difficult.

Below is a stripped down example of this.

void main() {
   auto b = new B([1, 2, 3, 4, 5, 6]);
}

class A {
   uint[] data;
   this(uint[] data) {
     this.data = data;
     init();  // This ends up calling B.init() and fails the 
invariant!
   }

   void init() {
     // Do some checking.
   }
}

class B : A {
   uint[] dataSlice;

   invariant() {
     assert(dataSlice !is null);
   }

   this(uint[] data) {
     super(data);
     dataSlice = data[3..$];
   }

   override void init() {
     // Do more checking;
     super.init();
   }
}

If the base class constructor needs to occur before the derived 
class constructor, is there a good way to solve this without 
getting rid of the invariant?

  - Vijay
Nov 11 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, November 12, 2012 04:32:51 Vijay Nayar wrote:
 If the base class constructor needs to occur before the derived
 class constructor, is there a good way to solve this without
 getting rid of the invariant?
Don't call virtual functions inside the constructor if you don't want any functions to invoke the derived class' invariant. If you need something done in the derived class, then do it in the derived class' constructor rather than a virtual function called by the base class constructor. - Jonathan M Davis
Nov 11 2012
prev sibling parent "Tobias Pankrath" <tobias pankrath.net> writes:
On Monday, 12 November 2012 at 03:32:52 UTC, Vijay Nayar wrote:
 I was working on a little project when I encountered something 
 odd.  Essentially a base class contains some data and a derived 
 class needs a slice of that data.  Certain properties of this 
 slice must be maintained, so the derived class has an invariant.

 What happens is that if the base class, even in the 
 constructor, calls a function that is overridden in the derived 
 class, the invariant gets invoked.  This can make 
 initialization quite difficult.

 Below is a stripped down example of this.

 void main() {
   auto b = new B([1, 2, 3, 4, 5, 6]);
 }

 class A {
   uint[] data;
   this(uint[] data) {
     this.data = data;
     init();  // This ends up calling B.init() and fails the 
 invariant!
   }

   void init() {
     // Do some checking.
   }
 }

 class B : A {
   uint[] dataSlice;

   invariant() {
     assert(dataSlice !is null);
   }

   this(uint[] data) {
     super(data);
     dataSlice = data[3..$];
   }

   override void init() {
     // Do more checking;
     super.init();
   }
 }

 If the base class constructor needs to occur before the derived 
 class constructor, is there a good way to solve this without 
 getting rid of the invariant?

  - Vijay
Make init private and don't override it.
Nov 12 2012