Achtung, das abstract hier kollidiert mit abstract und vielliecht sollte man es hier ändern.

GraphicObject contains                // enthält abstrakte Methoden, ergo nicht instanziierbar
{
  /* Dieses Objekt wird automatisch initialisiert */
    
  Name is         string : "Gunther";

  /* Dieses Objekt wird automatisch initialisiert, die Zuweisung ist aber überschreibbar */
    
  Type is virtual string : "unknown object";

  /* crude (unreif) erklärt, dass die Methode auch von unfertig konstruierten Objekten gerufen werden darf */
  OperatorAsString            is abstract crude method as string;  // <- abstract: Wird hier nicht definiert
  GetTypeDesc( TypeDesc ref ) is abstract method as bool;          // <- abstract: Wird hier nicht definiert
  

  /* Construct::body, destruct::body, copy::body und move::body rufen zuerst die Varianten ihrer Basisklasse auf. */
    
  construct
    /* Ruft eine unbenannte Funktion auf, die Type initialisiert */
  {
      print "Generiere {Type}\n";            // Type ist schon initialisiert
      print "Typ is {OperatorAsString()}\n"; // OperatorAsString darf vom Konstruktor aufgerufen werden
  }
  destruct is virtual;  // Wir haben abstrakte und virtuelle Funktionen, der Destruktor ist damit automatisch virtuell, aber man kann es ruhig auch sagen/per warning melden?
                        // ist virtuell, muss also nicht von abgeleiteten Klassen überschrieben werden
  
  copy( value is thistype ) abstract      // ist hier implementiert, verlangt aber, dass abgeleitete Klassen es ebenfalls implementieren.
  { /* Ohne Definition würde automatisch für beide Typen "copy" aufgerufen */
      Name : value.Name;
      Type : value.Type;
  }
  
  move( value is thistype rip )
  {
      Name : value.Name;  // value.name ist string rip, wir reißen also die Daten raus -> Rest in Peace
      Type : value.Type;  // value.Type ist string rip, wir reißen also die Daten raus -> Rest in Peace, das ganze landet also in string::move( string rip );
  }
  
  // Factory muss die Konstruktoren noch nicht kennen, solange sie später gültig auftauchen
  // Factory bekommt als Result einen GraphicsObject ptr. return muss also auch Speicher anfordern.
  // wenn die Funktion Fehlschlagen kann muss sie als thiytype ptr agieren
  
  create( value is string; x,y is double, r is double : 0. ) as thistype ptr
  {
      if( value == "Point"  ) return Point( x, y );                     
      if( value == "Circle" ) return Circle( Point(x,y), Radius(r) );
      
      fail;
  }
  
  // Kann sie hingegen nicht fehlschlagen, darf ein thistype ref erwartet werden
  create( value is TypeEnum; x,y is double, r is double : 0. ) //as thistype var ref
  {
      switch( value )
      {
          case TypeEnum::Point:  return Point( x, y );                     
          case TypeEnum::Circle: 
              assert( r ==! default );  // r muss gesetzt worden sein, sonst Kompilierabbruch (static_assert)
              assert( r ==! 0. );       // Laufzeitüberprüfung zu Debugzwecken, wird nur im Debugmode geloggt, kein fail.
              return Circle( Point(x,y), Radius(r) );
          // default nicht erforderlich, weil es nur die zwei Enums gibt, also alle Fälle abgedeckt sind
      }
      // hier kann man nicht ankommen, weil alle Pfade vorher in einem return enden
  }
};

c = GraphicObject.create( TypeEnum::Circle, 2, 3, 5 );
p = GraphicObject.create( TypeEnum::Point, 1, 2 );
cPtr = GraphicObject.create( "Circle", 4, 5 /* Radius ist 0 */ );


overrides Alternativen
swaps  statt overrides (anregung von Michael Bachnick)
change (michael)
shifts
passes


Point is GraphicObject
contains
{
    Type             swaps string : "Point";
    OperatorAsString swaps method : "Point";
    
    x,y              is    double : [0., 0.];  // Default-Initialisierung
    
    construct( x, y );
}

Radius contains double : 0;

Bla is Point(0,0), Radius(5);  // Objekt "Bla" wird gleich instanziiert, existiert also
Circle is Point, Radius;       // SecondCircle ist nur Typ, solange es nicht benutzt wird (also Funktionen gerufen werden oder Variablen abgefragt oder gesetzt werden)

MyCircle is Circle( Point(0,0), Radius(5) ); // Alle Konstruktoren werden bedient, MyCircle ist ein initialisiertes Circle-Objekt.