Das Folgende ist größtenteils richtig; Möglicherweise habe ich etwas übersehen oder etwas falsch verstanden; Lesen Sie das verlinkte Dokument (es ist zu kurz) und schreiben Sie es in die Kommentare – danke.
Schlechte Analogie : Eine Klasse ist ein Ausstecher. Eine Instanz ist ein Keks, der aus dem Keksausstecher hergestellt wird.
Problem mit der Analogie : Ich werde auch JSLs anrufen Klasse A Prototyp . Ein Prototyp ist ein tatsächlicher Cookie. Der Prototyp-Cookie könnte gegessen oder verändert werden, aber normalerweise würde man das nicht tun wollen. Stattdessen sollten Sie den Umriss des Keksteigs nachzeichnen und ihn mit einer Schere ausschneiden, um neue Keksinstanzen herzustellen. Wenn Sie jedoch aus dem Prototyp-Cookie herausbeißen, werden auch alle zukünftigen Cookie-Instanzen so aussehen, als wären sie zerbissen (zweites Beispiel). Außerdem wird die Methode _init_(...) nicht für den Prototyp-Cookie ausgeführt, sodass er möglicherweise halbfertig ist, aber die richtige Form hat.
Der Dokumentation Verwendet Vorlage statt Prototyp . Ich bevorzuge Prototypen gegenüber Vorlagen; Ein Prototyp ist ein verwendbares Objekt, während eine Vorlage lediglich zeigt, wohin die Sprühfarbe gelangen soll. Für das erste Beispiel spielt dieser subtile Unterschied keine Rolle.
Ein einfaches Beispiel
Dies ist ein einfaches Einzelklassenbeispiel für Blase . Der Klassenprototyp wird von DefineClass() erstellt. NewObject() macht 61 tatsächliche Exemplare des Prototyps. Jede der 61 Instanzen hat einen Radius und ein XY-Zentrum. Der Prototyp stellt außerdem Methoden für _init_(...), drift() und draw() bereit. Mithilfe des Objekts wird ein Diagramm angezeigt Zeichenmethode für jedes Objekt. Dann wird eine Schleife ausgeführt, die die Objektdriftmethode für jedes Objekt aufruft und dann das Diagramm anweist, neu zu zeichnen. Das Ergebnis ist ein animiertes Diagramm wie dieses:
Die JSL für das Diagramm:
// define a simple class (like a template) to represent a 2D bubble
Define Class("bubble",
// class member variables
m_radius = .; // class member variables are specified in
m_xpos = .; // the class definition with initial values.
m_ypos = .; // these values are copied into instances created by NewObject(...)
// class methods
_init_ = Method( {radius, x, y}, // called by NewObject(bubble(r,x,y)) below to initialize an instance
this:m_xpos = x; // this: is the namespace of an instance
m_ypos = y; // you don't need "this:" unless the member name is
m_radius = radius; // the same as a parameter name
);
drift = Method( {}, // a method to move the bubble
m_xpos = m_xpos * 0.995;// tentatively drift to center
m_ypos = m_ypos * 0.995;
);
draw = Method( {}, // a method to draw the bubble
Circle( {m_xpos, m_ypos}, m_radius )
);
);
// make a bunch of instances of the bubble class, keep them in a list
bubblelist = {};
For( i = 1, i <= 61, i += 1,
Insert Into( bubblelist,
// each instance of bubble is initialized with a random radius and position
New Object( bubble( Random Uniform( .03, .8 ), Random Uniform( -.9, .9 ), Random Uniform( -.9, .9 ) ) )
)
);
picno = 0; // need an ID for each picture
// make a window to display all the instances of the bubble class
New Window( "bubble class instances",
gb = Graph Box( // the graphic script for the graph box scales and sizes the axes and...
xaxis( {Add Ref Line( 0, "Solid", "Black", "", 1 )} ),
yaxis( {Add Ref Line( 0, "Solid", "Black", "", 1 )} ),
framesize( 600, 600 ),
X Scale( -1, 1 ),
Y Scale( -1, 1 ),
// the graphic script tells each bubble to draw itself
For( i = 1, i <= N Items( bubblelist ), i += 1,
bubblelist[i]:draw()
);
text({-.9,-.9},char(picno)),
<<ONCLOSE></ONCLOSE>Mein mentales Modell dafür, wie es funktioniert: Unter der Decke führt DefineClass() eine versteckte Liste aller DefineClass()-Prototypen und sie sehen aus eine Menge wie Instanzen. Mehr dazu gleich; Im obigen Beispiel wird über die Funktion NewObject() auf sie zugegriffen. NewObject() klont eine neue Instanz des Prototypobjekts und führt die _init_-Methode aus.
Was ist Das: ?
Im obigen Beispiel habe ich die Mitgliedsvariablen mit benannt M_ Präfix. Das ist nicht erforderlich, kann aber nützlich sein, um sich zu merken, welche Variablen Mitgliedsvariablen sind, und um Kollisionen mit Parameternamen und Namen lokaler Variablen zu verhindern. Aber ich habe auch verwendet this:m_xpos bei einer der _init_()-Methodenzuweisungen. Der Das: Namespace bedeutet „die Mitgliedsvariable der aktuellen Instanz“. So dies:x = x; kann verwendet werden, wenn Sie möchten, dass die Mitgliedsvariable x und der Parameter x denselben Namen haben. M_ wird für die nächste Person, die Ihren Code pflegt, einfacher sein.
Was ist Blase: ?
Es gibt einen anderen Namensraum die man meistens nicht braucht Das wird zeigen, warum ich gesagt habe, dass die DefineClass()-Prototypen in der versteckten Liste aussehen eine Menge wie Instanzen – der Klassenname Ist ein Namensraum. Benutzen Blase:m_radius greift auf den m_radius des Prototyps zu, auch über eine Instanzmethode. Wenn Sie der Meinung sind, dass Sie eine statische Mitgliedsvariable benötigen, ist dies eine Möglichkeit, eine zu erstellen ... wenn Sie vorsichtig sind.
Verwendung des Prototyps für statische Werte
Das nächste Beispiel verwendet eine statische m_ID-Variable. Wie aus den Kommentaren hervorgeht, hätte ich wahrscheinlich eine andere Variante machen sollen, aber diese ist immer noch nützlich, weil sie die Warnung „Wenn Sie vorsichtig sind“ erklärt. Folgendes passiert (wieder mein mentales Modell):
Wenn _init_() unten ausgeführt wird, hat die Klasse bubble2 bereits den gesamten Prototypinhalt in die neue Instanz kopiert. Die neue Instanz verfügt über eine Kopie der m_id des Prototyps. _init_() ändert dann die m_id() im Prototyp. Die nächste Instanz erhält den geänderten Wert. Die anderen Mitgliedsfunktionen müssen zwischen der m_id im Prototyp (bubble2:m_id) und this:m_id (oder einfach nur m_id ohne Namespace) wählen. Hier verwenden sie m_id, eine Kopie einer für die Instanz eindeutigen Ganzzahl.
Im Video fügt sich das letzte Puzzleteil bei 5:15 am unteren Bildschirmrand ein. Die schwarzen Kreise sind Bubble2s, die ihren m_id-Wert anzeigen. Sie verwenden die m_id, um sicherzustellen, dass sie sich selbst ignorieren, wenn sie alle nahen Nachbarn untersuchen.
// twist is a scaling divisor for a shearing rotation that moves
// the outer edge faster.
// this value needs to get bigger with more beehive cells.
global:twist = 600;
// choose the size to make them fit, but it also interacts with twist
// because the distance from the center grows
global:bubblesize = 0.057;
// use a defined class to represent each cell in the beehive.
Define Class("bubble2",
m_radius = .; // in the video, all beehive cells have the same radius
m_xpos = .; // the beehive cell's position
m_ypos = .;
//
// this is answering the question "can a JSL Class have a static member variable?"
// this could have been done more intuitively for this example by passing the
// index of the creation loop to the _init_ code, but here it is...initialize the
// "static" value to 1...
m_id = 1; // keep reading to understand the two-faced nature of this variable...
// What actually happens: when newObject(bubble2(...)) makes a new instance, the _init_(...)
// is called.
// First, the m_id is cloned from the prototype to the instance. The first instance gets m_id==1.
// Second, the bubble2: namespace causes the prototype class to increment the
// prototype's m_id. The next instance gets the new value from the prototype, m_id==2.
// this is a little odd, coming from a C++ -like language; in the drift method below,
// "other:m_id != m_id" both m_id values are regular non-static instance members.
// if you want the static behaviour, use the bubble2:m_id approach (bubble2 is the class
// name and access the singleton in the prototype class.)
// Normally you *never* want to use the class name as a name space qualifier because
// you set up the class correctly and initialize via _init_( parameters ). And normally
// a static value is also a constant value, so using a copy is just fine. But if
// multiple instances need to communicate via a singleton static, AND you always use
// the namespace, this is a reasonable place to keep the static.
// Having written all that, I now dislike this particular example because it is using
// a confusing combination of bubble2:m_id and instance values of m_id.
_init_ = Method( {radius, x, y},
m_radius = radius;
this:m_xpos = x; // this: (or nothing) operates on an instance
m_ypos = y;
bubble2:m_id++; // bubble2: operates on the prototype. The next newobject(bubble2(...)) uses the modified prototype
);
distanceBetweenCenters = Method( {other},
/*return*/ Sqrt( (m_xpos - other:m_xpos) ^ 2 + (m_ypos - other:m_ypos) ^ 2 )
);
distanceBetweenEdges = Method( {other}, // negative: overlaps
/*return*/ distanceBetweenCenters( other ) - (m_radius + other:m_radius)
);
drift = Method( {},
// bubbles should pull to 0,0 AND move away from near bubbles
angle = ATan( m_ypos, m_xpos );
radius = Sqrt( m_ypos ^ 2 + m_xpos ^ 2 );
shear = global:twist; // also depends on number of circles
shrink = .99950;
// radius/shear creates a tiny amount of rotation, more on the edges. That rotational
// shearing helps the circles bounce about. /400 is not enough and /100 is too much.
// radius*shrink pulls all the circles to the origin. It is balanced by push, below.
x = Cos( angle + radius / shear ) * radius * shrink;
y = Sin( angle + radius / shear ) * radius * shrink;
// check neighbors
{neighbors, distances} = kdt << kNearestRows( 7, m_id );
tension = 0;
ntension = 0; // calculate a tension, or stress, for contour to use as a color
For( iN = 1, iN <= N Items( neighbors ), iN += 1,
i = neighbors[iN];
other = bubblelist[i];
If( other:m_id != m_id, // <<<<<<<<<<<<<<<< NOT the bubble2:m_id value !!!
dist = distanceBetweenEdges( other );
// if the dist is zero, it is perfect. if the other guy is far away, ignore him.
If( Abs( dist ) < global:bubblesize * 0.8,
tension += dist ^ 2; // this will be a RMS value at the bottom
ntension += 1;
);
If( dist < 0, //push
angle = ATan( m_ypos - other:m_ypos, m_xpos - other:m_xpos );
x += Cos( angle ) * Abs( dist ) ^ .4 * .05;
y += Sin( angle ) * Abs( dist ) ^ .4 * .05;
);//
, //
Beep()
);
);
m_xpos = x;
m_ypos = y;
If( ntension == 0,
ntension = 1;
tension += (global:bubblesize / 2) ^ 2;
);
Sqrt( tension / ntension ); // RMS
);
draw = Method( {},
Transparency( .8 );
Circle( {m_xpos, m_ypos}, m_radius, "FILL" );
Transparency( 1 );
Text( center justified, {m_xpos, m_ypos - m_radius * .2}, Char( m_id ) );
);
);
bubblelist = {};
n = 12; // how many "rings" of hex cells
m = -26 + 21 * n + 3 * (n - 3) ^ 2; // yes, I used JMP to get this formula
For( i = 1, i <= m, i += 1,
Insert Into(
bubblelist,
New Object( bubble2( Random Uniform( global:bubblesize, global:bubblesize ), Random Uniform( -.9, .9 ), Random Uniform( -.9, .9 ) ) )
)
);
// need a table for contour plot, and it will include 100 values in a circle around the hive
ring = 100;
dt = New Table( "tension",
Add Rows( m + ring ),
New Column( "x", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "y", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "tension", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) )
);
For( i = 1, i <= ring, i += 1,
angle = 2 * Pi() * i / ring;
dt:x[m + i] = 1.25 * Sin( angle );
dt:y[m + i] = 1.25 * Cos( angle );
dt:tension[m + i] = 0;
);
cplot = dt << Contour Plot(
X( :x, :y ),
Y( :tension ),
Show Data Points( 0 ),
Fill Areas( 1 ),
Label Contours( 0 ),
Transform( "Range Normalized" ),
Color Theme( "Green Yellow Red" ),
Specify Contours( Min( 0 ), Max( .01 ), N( 50 ) )
);
Report( cplot )[framebox( 1 )] << Frame Size( 1920, 1080 ) << maximizewindow( 1 ) << backgroundcolor( "black" );
Report( cplot )[framebox( 1 )] << xaxis(
{Format( "Fixed Dec", 12, 3 ), Min( -1.4*1920/1080 ), Max( 1.4*1920/1080 ), Inc( 0.5 ), Label Row(
{Show Major Grid( 0 ), Show Major Labels( 0 ), Show Major Ticks( 0 ), Show Minor Grid( 0 ), Show Minor Labels( 0 ), Show Minor Ticks( 0 )}
)}
);
Report( cplot )[framebox( 1 )] << yaxis(
{Format( "Fixed Dec", 12, 3 ), Min( -1.4 ), Max( 1.4 ), Inc( 0.5 ), Label Row(
{Show Major Grid( 0 ), Show Major Labels( 0 ), Show Major Ticks( 0 ), Show Minor Grid( 0 ), Show Minor Labels( 0 ), Show Minor Ticks( 0 )}
)}
);
// here is the script that makes the bubbles draw
Report( cplot )[framebox( 1 )] << addgraphicsscript(
Fill Color( "black" );
text Color( "white" );
pen Color( rgbcolor(64,64,64) );
For( i = 1, i <= N Items( bubblelist ), i += 1,
bubblelist[i]:draw()
);
hline(0);
vline(0);
);
cplot << onclose(
keepRunning = 0;
Close( dt, nosave );
1;
);
Wait( 0 );
//dir = "$temp\ClassWithStatic" || Char( global:twist ) || "\";
//Delete Directory( dir );
//Create Directory( dir );
//Write( Convert File Path( dir, "windows" ) );
picno = 0;
keepRunning = 1;
While( keepRunning,
xy = J( N Items( bubblelist ), 2, . );
For( i = 1, i <= N Items( bubblelist ), i += 1,
xy[i, 1] = bubblelist[i]:m_xpos;
xy[i, 2] = bubblelist[i]:m_ypos;
);
// the kdtable makes it faster to find near neighbors
kdt = KDTable( xy );
For( i = 1, i <= N Items( bubblelist ), i += 1,
dt:tension[i] = bubblelist[i]:drift();
dt:x[i] = bubblelist[i]:m_xpos;
dt:y[i] = bubblelist[i]:m_ypos;
);
Report( cplot )[framebox( 1 )] << inval << updatewindow;
picno += 1;
// Report( cplot )[framebox( 1 )] << save picture( dir || Char( (picno) + 1e6 ) || ".png" );
Wait( .01 );
);
Beide obigen Beispiele hätten genauso einfach (vielleicht einfacher) mit Zeilen einer Datentabelle zur Darstellung von Objekten und Spalten zur Darstellung von Mitgliedsvariablen und JSL-Benutzerfunktionen für die Methoden erstellt werden können. Die Verwendung von Klassen, insbesondere ohne Unterklassen, kann es für andere Personen schwieriger machen, Ihrer JSL zu folgen, wenn sie mit Klassen in JSL nicht vertraut sind.
Apropos Funktionen: Das Dokument für DefineClass erwähnt sie auch. Soweit ich weiß, bringen sie fast nichts und sollten wahrscheinlich vermieden werden. Ich denke, jede Instanz einer Klasse erhält wahrscheinlich eine separate Kopie jeder Methode und jeder Mitgliedsvariablen. Wenn Sie eine Function() definieren und sie in einer Mitgliedsvariablen speichern, erstellen Sie lediglich etwas anderes zum Kopieren, das (vielleicht) mit nur einer einzigen Kopie in einem globaleren Namespace hätte liegen können. Aber wenn es nur eine einzige (oder sehr wenige) Instanzen gibt und Sie wirklich eine Funktion für die Klasse benötigen, die außer ihren Parametern nichts kennt, dann ist vielleicht eine Funktion in einer Klasse das, was Sie brauchen.
Kommen wir zum letzten Beispiel. Lassen Sie uns einige Unterklassen erstellen und uns den letzten Namespace ansehen. super: , nach dem ich suchen musste (siehe Kommentare in JSL).
Intuitives Beispiel : Eine Basisklasse könnte ein Fahrzeug sein, Unterklassen (oder abgeleitete Klassen) sind Lastkraftwagen und Autos. Ein LKW könnte die Navigationsmethode der Basisklasse durch eine Methode ersetzen, die Wohnstraßen meidet. Ein Auto könnte die HOV-Spuren nutzen. Eine Liste von Fahrzeugen wird jeweils das Richtige tun, wenn sie angewiesen werden, von A nach B zu navigieren.
Define Class hat ein interessantes Argument: Basisklasse(...) . Im Beispiel unten, Form wird die Basisklasse sein und Quadrat Und Kreis wird aus der Form abgeleitet. Das Beispiel erstellt eine Liste von Quadraten und Kreisen und zeigt sie an.
two squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledtwo squares, two circles, two outlined, two filledzwei Quadrate, zwei Kreise, zwei umrandet, zwei gefüllt
Die folgende Beschreibung basiert auf Versuch und Irrtum; Ich glaube, dass es korrekt genug ist, um ein hilfreiches Modell zur Vorhersage zu sein, wie etwas funktionieren wird.
Was ist super: ?
Wenn eine abgeleitete Klasse erstellt wird, wird JMP bis zum Ende der Klasse ausgeführt Basisklasse Kette und arbeitet zurück nach oben, wobei zuerst Basisklassen und in ihren eigenen Namensräumen erstellt werden. Die Namespaces sind intern miteinander verknüpft, sodass eine abgeleitete Klasse auf eine Mitgliedsvariable verweisen kann, indem sie in ihrem eigenen Namespace sucht und dann der Namespace-Kette bis zur Basisklasse folgt, bis sie die Variable findet. Der super : Namespace bedeutet nur, einmal in der Namespace-Kette vorwärts zu springen, ohne im aktuellen Namespace zu suchen. Aus diesem Grund heißt es in der folgenden JSL: „Verwenden Sie super: nicht, um eine Basismethode aufzurufen, wenn Sie dies nicht benötigen“; Die Basismethode hat keinen Zugriff auf den abgeleiteten Namespace und kann daher keine abgeleitete Funktion aufrufen.
Mehrfachvererbung: Wenn Sie „Schnittstellen“ verwenden und doppelte Namen vermeiden, könnte es funktionieren. Viel Glück. Ich bin mir nicht sicher, wo eine Geschwister-Basisklasse in die Namespace-Kette im obigen Modell passt.
// demonstrates JMP class inheritance and overriding a method
// and calling the super class. A circle and a square class
// are derived from a shape class. Explains when to NOT use super:.
//
// I found super: in https://github.com/sassoftware/jsl-hamcrest/blob/master/Source/Core/Matchers/EqualTo.jsl
// it isn't documented anywhere else, but works great for calling base class _init_
// Also, https://github.com/sassoftware/jsl-hamcrest/blob/master/Source/Core/Utils.jsl
// shows a "self" implementation idea. This is a bad idea because it creates a circular reference
// that must be cleared before the object is lost/deleted...or it will leak.
// avoid making members and methods in base and derived classes with the same name.
// _init_, _to string_, _show_ are exceptions, but they must not try to use a derived
// class member or method. (you would not normally want to, so no problem.)
//
// avoid needless upcast (super:); it cripples the base class because there is no downcast or
// virtual mechanism. Without the upcast, a baseclass function runs with access to the
// derived class members and methods. (see square's draw method calling docolor calling record.)
//
// it appears that the derived chain is searched *after* the current class; in a two class
// (base,derived) example that inverts the search order for members and methods when a
// derived class uses "super:" to call a base class method. If the base class calls a "virtual"
// function that exists in both base and derived, it won't get the derived one if "super:" was
// used but will if no scope is used. You only need "super:" typically when you want to call
// the base class method from an overridden method of the same name. If the base class method
// isn't calling back to derived via a virtual, everything is good.
// deep details
//
// the output shows lines like this:
// record square=square(shape=(s= x=30 y=30 r=5 s=4 c=yellow f=1))
// record circle=circle(shape=(s= x=30 y=60 r=10 s=99 c=green f=0))
//
// the square and the circle both get the right answer via different
// paths. Because of way draw() is overridden by square and not by circle,
// the initial call, objects[window:i] << draw(), is calling either a
// derived member or a base member. In both cases, "this" is for the
// derived member. in square's draw(), I made an error, now commented
// out: /*super:*/docolor(), that caused docolor to run with "this"
// for the base class, not the derived class. docolor then calls record().
// all three classes have record() members. The intent is to override the
// base class version ("never seen"). The error caused the base class
// version to run for square because "this" of docolor() was for the base class.
Define Class( "shape", // base class for both shapes
m_Xcenter = .;
m_Ycenter = .;
m_radius = .;
m_sides = .;
m_color = .;
m_filled = .;
_init_ = Method( {x, y, radius, sides, color, fill},
m_Xcenter = x;
m_Ycenter = y;
m_radius = radius;
m_sides = sides;
m_color = color;
m_filled = fill;
);
_to string_ = Method( {},
"shape=(s=" ||
" x=" || Char( m_Xcenter ) || " y=" || Char( m_Ycenter ) ||
" r=" || Char( m_radius ) || " s=" || Char( m_sides ) ||
" c=" || Char( m_color ) || " f=" || Char( m_filled ) || ")"
);
_show_ = _to string_;
// the following should NOT ever get called because square and circle override it
// try changing square to call super:docolor and then you'll see this
record=method({},show("never seen, overridden by square and circle"));
// both shapes understand filled vs outlined
// see note in square:draw method about calling docolor without super:
docolor = Method( {},
this:record(); // this: doesn't change anything,
If( this:m_filled, // it is mostly for disambiguating
Fill Color( /*this:*/m_color );// parameter of same name
, //
Pen Color( this:m_color )
)
);
// the base class has a draw method that circle uses;
// square provides an override because this draws a
// diamond-oriented square
draw = Method( {},
docolor();
p = J( m_sides, 3, 2 );//2==draw
p[1, 3] = 1;//1==move
p[m_sides, 3] = -2;//-2==draw and close
For( i = 1, i <= m_sides, i += 1,
p[i, 1] = m_Xcenter + m_radius * Cos( 2 * Pi() * i / m_sides );
p[i, 2] = m_Ycenter + m_radius * Sin( 2 * Pi() * i / m_sides );
);
Path( p, m_filled );
);
);
Define Class( "circle", baseclass( shape ),
_init_ = Method( {x, y, radius, color, fill},
super:_init_( x, y, radius, 99/*sides*/, color, fill )
);
_to string_ = Method( {},
"circle(" || super:_tostring_() || ")"
);
_show_ = _to string_;
record=method({},write("\!nrecord circle=",_show_()));
// circle has no override for draw()
);
Define Class( "square", baseclass( shape ),
_init_ = Method( {x, y, radius, color, fill},
super:_init_( x, y, radius, 4/*sides*/, color, fill )
);
_to string_ = Method( {},
"square(" || super:_tostring_() || ")"
);
_show_ = _to string_;
record=method({},write("\!nrecord square=",_show_()));
// square overrides the base class draw
draw = Method( {},
/*super:*/docolor();// don't up-cast, docolor can't down-cast and gets base class record()
Rect(
m_Xcenter - m_radius,
m_Ycenter - m_radius,
m_Xcenter + m_radius,
m_Ycenter + m_radius,
m_filled
);
);
);
objects = {};
Insert Into( objects, New Object( square( 30, 30, 5, "yellow", 1 ) ) );
Insert Into( objects, New Object( Circle( 30, 60, 10, "green", 0 ) ) );
Insert Into( objects, New Object( square( 60, 30, 15, "blue", 0 ) ) );
Insert Into( objects, New Object( Circle( 60, 60, 20, "red", 1 ) ) );
New Window( "objects",
gb = Graph Box( framesize( 500, 500 ),
For( window:i = 1, window:i <= N Items( objects ), window:i += 1,
//Show( objects[i] );
objects[window:i] << draw(); // uses the base class or the derived class draw
)
)
);
//stop();
// animate the color of object 4, the big red circle
For( i = 0, i <= 1, i += (1 / 256), //show(i);
objects[4]:m_color = HLS Color( i, .5, 1 );
gb << inval << updatewindow;
Wait( 0 );
);
Wie wäre es mit Das ?
C++ hat einen Wert namens „this“ (andere Sprachen verwenden „self“ und „me“), der manchmal benötigt wird, damit ein Objekt auf sich selbst verweist. Nicht dasselbe wie dieses: Namespace-Präfix. Ich glaube nicht, dass die JSL-Klasse ein „this“ innerhalb der Klasse bietet, und Sie könnten versucht sein, eines wie dieses zu erstellen:
x = newObject(myClass(17));
x::self = x;
oder so ähnlich. Dann könnte eine myClass-Methode „self“ verwenden, um Dinge zu tun, die eine Klasseninstanz erfordern, wie zum Beispiel das Klonen.
Scripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceScripting index showing messages that can be sent to a class instanceSkriptindex, der Nachrichten anzeigt, die an eine Klasseninstanz gesendet werden können
Das Beibehalten einer Mitgliedsvariablen in einer Klasseninstanz, die die Klasseninstanz (einen Zeiger auf sie) enthält, kann zu einem Speicherverlust führen. Das bringt uns zu einem neuen Thema ... eigentlich Themen.
Wann wird eine Instanz gelöscht?
Eine Instanz wird gelöscht, wenn keine Verweise darauf vorhanden sind. Im obigen Abschnitt verhindert ein „Selbst“-Verweis innerhalb einer Instanz, dass die Instanz gelöscht wird. selbst wenn Sie alle Ihre Handles für die Instanz verloren haben . Es gibt keine andere Möglichkeit, es zu bereinigen, als JMP zu schließen.
Wann wird eine Instanz kopiert?
Das Beste daran: Eine Instanz wird nur kopiert, wenn Sie die <Dies bedeutet, dass Instanzen als Referenz übergeben werden.Yay! Es ist viel weniger umständlich, eine einfache Klasse zum Umschließen einer großen Matrix zu erstellen und eine Instanz der Klasse an eine Benutzerfunktion zu übergeben, anstatt JMP eine Kopie des Matrixarguments in den Parameterwert erstellen zu lassen und möglicherweise eine weitere Kopie zurückzugeben.