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.