Ce qui suit est généralement correct ; J'ai peut-être manqué quelque chose ou mal compris quelque chose; lisez le document lié (il est trop court) et lancez-vous dans les commentaires - merci.
Mauvaise analogie : une classe est un emporte-pièce. Une instance est un cookie fabriqué à partir de l'emporte-pièce.
Problème d'analogie : je vais aussi appeler les JSL classe un prototype . Un prototype est un vrai cookie. Le cookie prototype pourrait être mangé ou modifié, mais vous ne voudriez normalement pas le faire. Au lieu de cela, vous devez tracer son contour dans la pâte à biscuits et le couper avec des ciseaux pour créer de nouvelles instances de biscuits. Mais si vous prenez une bouchée du cookie prototype, toutes les futures instances de cookie auront également l'air mordues (deuxième exemple). De plus, la méthode _init_(...) n'est pas exécutée pour le cookie prototype, il peut donc être à moitié cuit, mais il a la bonne forme.
Le Documentation les usages modèle plutôt que prototype . Je préfère le prototype au modèle ; un prototype est un objet utilisable tandis qu'un modèle montre simplement où la peinture en aérosol doit aller. Cette distinction subtile n'a pas d'importance pour le premier exemple.
Un exemple simple
Il s'agit d'un exemple simple à classe unique pour bulle . Le prototype de classe est créé par DefineClass(). NouvelObjet() fait 61 instances réelles du prototype. Chacune des 61 instances a un rayon et un centre x,y. Le prototype fournit également des méthodes pour _init_(...), drift() et draw(). Un graphique est affiché à l'aide de l'objet méthode draw pour chaque objet. Ensuite, une boucle s'exécute, appelant la méthode de dérive d'objet pour chaque objet, puis demandant au graphique de se redessiner. Le résultat est un graphique animé comme celui-ci :
Le JSL pour le graphique :
// 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>Mon modèle mental pour la façon dont cela fonctionne : sous les couvertures, DefineClass() garde une liste cachée de tous les prototypes DefineClass() et ils regardent beaucoup comme des instances. Plus à ce sujet dans un instant; l'exemple ci-dessus y accède via la fonction NewObject(). NewObject() clone une nouvelle instance de l'objet prototype et exécute la méthode _init_.
Qu'est-ce que ce: ?
Dans l'exemple ci-dessus, j'ai nommé les variables membres avec m_ préfixe. Ce n'est pas obligatoire, mais cela peut être utile à la fois pour se rappeler quelles variables sont des variables membres et pour éviter les collisions avec les noms de paramètres et les noms de variables locales. Mais j'ai aussi utilisé ceci : m_xpos sur l'une des affectations de méthode _init_(). Le ce: namespace signifie "la variable membre de l'instance actuelle". Donc ceci :x = x ; peut être utilisé si vous souhaitez que la variable membre x et le paramètre x aient le même nom. m_ sera plus facile pour la prochaine personne qui maintiendra votre code.
Qu'est-ce que bulle: ?
Il y a un autre espace de noms dont vous n'avez généralement pas besoin cela montrera pourquoi j'ai dit les prototypes DefineClass () dans la liste cachée beaucoup comme instances--le nom de la classe est un espace de noms. En utilisant bulle:m_rayon accédera au m_radius du prototype, même à partir d'une méthode d'instance. Si vous pensez avoir besoin d'une variable membre statique, c'est une façon d'en créer une... si vous faites attention.
Utilisation du prototype pour les valeurs statiques
L'exemple suivant utilise une variable m_ID statique. Comme les commentaires le suggèrent, j'aurais probablement dû faire une variante différente, mais celle-ci est toujours utile car elle explique l'avertissement "si vous faites attention". Voici ce qui se passe (mon modèle mental, encore une fois):
Lorsque le _init_() ci-dessous s'exécute, la classe bubble2 a déjà copié tout le contenu du prototype dans la nouvelle instance. La nouvelle instance a une copie du m_id du prototype. _init_() change alors le m_id() dans le prototype. L'instance suivante obtient la valeur modifiée. Les autres fonctions membres doivent choisir entre le m_id dans le prototype (bubble2:m_id) et this:m_id (ou juste m_id sans espace de noms). Ici, ils utilisent m_id qui est une copie d'un entier unique à l'instance.
Dans la vidéo, la dernière pièce du puzzle se met en place à 5h15 sur le bord inférieur de l'écran. Les cercles noirs sont des bubble2 qui affichent leur valeur m_id. Ils utilisent le m_id pour s'assurer de s'ignorer lorsqu'ils étudient tous les voisins proches.
// 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 );
);
Les deux exemples ci-dessus auraient pu tout aussi facilement (peut-être plus facilement) être construits avec des lignes d'une table de données pour représenter des objets et des colonnes pour représenter des variables membres et des fonctions utilisateur JSL pour les méthodes. L'utilisation de classes, en particulier sans aucune sous-classe, peut rendre votre JSL plus difficile à suivre pour quelqu'un d'autre s'il n'est pas à l'aise avec les classes en JSL.
En parlant de Functions, la doc de DefineClass les mentionne également. Autant que je sache, ils n'apportent presque rien à la table et devraient probablement être évités. Je pense que chaque instance d'une classe reçoit probablement une copie distincte de chaque méthode et de chaque variable membre. Si vous définissez une fonction () et la stockez dans une variable membre, vous créez simplement quelque chose d'autre à copier qui (peut-être) aurait pu être dans un espace de noms plus global avec une seule copie. Mais s'il n'y aura qu'une seule instance (ou très peu) et que vous avez vraiment besoin d'une fonction pour la classe qui ne connaît rien d'autre que ses paramètres, eh bien peut-être qu'une fonction dans une classe est ce dont vous avez besoin.
Passons au dernier exemple, faisons quelques sous-classes et regardons le dernier espace de noms, super: , que j'ai dû chercher (voir les commentaires dans JSL).
Exemple intuitif : une classe de base peut être un véhicule, les sous-classes (ou classes dérivées) sont les camions et les voitures. Un camion peut remplacer la méthode de navigation de la classe de base par une autre qui sait éviter les rues résidentielles. Une voiture pourrait profiter des voies réservées aux VOM. Une liste de véhicules fera chacun la bonne chose lorsqu'on lui dit de naviguer de A à B.
Define Class a un argument intéressant : classe de base(...) . Dans l'exemple ci-dessous, forme sera la classe de base et carré et cercle sera dérivé de la forme. L'exemple crée une liste de carrés et de cercles et les affiche.
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 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 filleddeux carrés, deux cercles, deux contours, deux remplis
La description suivante est basée sur des essais et des erreurs ; Je pense que c'est suffisamment correct pour être un modèle utile pour prédire comment quelque chose fonctionnera.
Qu'est-ce que super: ?
Lorsqu'une classe dérivée est créée, JMP s'exécute jusqu'à la fin de la classe de base chain et remonte vers le haut, en créant d'abord des classes de base, et dans leurs propres espaces de noms. Les espaces de noms sont liés entre eux en interne afin qu'une classe dérivée puisse référencer une variable membre en regardant dans son propre espace de noms, puis en suivant la chaîne d'espaces de noms jusqu'à la classe de base jusqu'à trouver la variable. Le super : l'espace de noms signifie simplement avancer une fois dans la chaîne d'espaces de noms sans regarder dans l'espace de noms actuel. C'est pourquoi le JSL ci-dessous dit "n'utilisez pas super: pour appeler une méthode de base si vous n'en avez pas besoin" ; la méthode de base n'aura pas accès à l'espace de noms dérivé et ne pourra donc pas appeler une fonction dérivée.
Héritage multiple : si vous utilisez des "interfaces" et évitez les noms en double, cela peut fonctionner. Bonne chance. Je ne sais pas où une classe de base sœur s'intègre dans la chaîne d'espaces de noms dans le modèle ci-dessus.
// 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 );
);
Qu'en est-il de ce ?
C++ a une valeur nommée "this" (d'autres langages utilisent "self" et "me") qui est parfois nécessaire pour qu'un objet se réfère à lui-même. Ce n'est pas la même chose : préfixe d'espace de noms. Je ne pense pas que la classe JSL propose un "ceci" dans la classe, et vous pourriez être tenté d'en créer un comme celui-ci:
x = newObject(myClass(17));
x::self = x;
Ou quelque chose proche de cela. Ensuite, une méthode myClass pourrait utiliser "self" pour faire des choses qui nécessitent une instance de classe, comme le clonage.
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 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 instanceIndex de script affichant les messages pouvant être envoyés à une instance de classe
Conserver une variable membre dans une instance de classe qui contient l'instance de classe (pointeur vers) peut créer une fuite de mémoire. Cela nous amène à un nouveau sujet... des sujets en fait.
Quand une instance est-elle supprimée ?
Une instance est supprimée lorsqu'il n'existe aucune référence à celle-ci. Dans la section ci-dessus, une référence "self" à l'intérieur d'une instance empêchera la suppression de l'instance, même si vous avez perdu tous vos identifiants pour l'instance . Il n'y a aucun moyen de le nettoyer, autre que de fermer JMP.
Quand une instance est-elle copiée ?
Voici le meilleur : une instance n'est copiée que si vous utilisez la méthode <Cela signifie que les instances sont passées par référence.Yay! Beaucoup moins maladroit de créer une classe simple pour envelopper une grande matrice et transmettre une instance de la classe à une fonction utilisateur, au lieu de demander à JMP de faire une copie de l'argument de la matrice dans la valeur du paramètre, et éventuellement de renvoyer une autre copie.