以下大部分是正確的;我可能錯過了一些事情或者誤解了一些事情;閱讀鏈接的文檔(它太短了)並在評論中大放異彩 - 謝謝。
不好的類比:一個類就是一個千篇一律的東西。 一個例子是用餅乾切割機製作的餅乾。
類比問題: 我也準備打電話給JSL班級A原型。 原型是一個實際的 cookie。 原型 cookie可以被吃掉或被修改,但你通常不想這樣做。 相反,您應該在餅乾麵團中描出其輪廓,然後用剪刀將其剪開以製作新的餅乾實例。 但是,如果您確實咬了原型 cookie,則所有未來的 cookie 實例也會看起來被咬了(第二個示例)。 另外,_init_(...) 方法不是針對原型 cookie 運行的,因此它可能是半生不熟的,但它具有正確的形狀。
這文檔用途模板而不是原型。 與模板相比,我更喜歡原型;原型是一個可用的對象,而模板只是顯示噴漆應該去的地方。 對於第一個例子來說,這種微妙的區別並不重要。
一個簡單的例子
這是一個簡單的單類示例氣泡。 類原型由 DefineClass() 創建。 NewObject() 使得原型中的 61 個實際實例。 61 個實例中的每一個都有一個半徑和一個 x,y 中心。 該原型還提供了 _init_(...)、drift() 和 draw() 方法。 使用對象顯示圖形每個對象的繪製方法。 然後運行一個循環,為每個對象調用對象漂移方法,然後告訴圖形重新繪製。 結果是一個像這樣的動畫圖:
該圖的 JSL:
// 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>我對其工作原理的心智模型:在幕後,DefineClass() 保留了所有 DefineClass() 原型的隱藏列表,它們看起來很多像實例一樣。 稍後會詳細介紹;上面的示例通過 NewObject() 函數訪問它們。 NewObject() 克隆原型對象的新實例並運行 _init_ 方法。
什麼是這: ?
在上面的示例中,我將成員變量命名為米_字首。 這不是必需的,但它對於記住哪些變量是成員變量以及防止與參數名稱和局部變量名稱發生衝突非常有用。 但我也用過這個:m_xpos在 _init_() 方法分配之一上。 這這:命名空間的意思是“當前實例的成員變量”。 所以這個:x = x;如果您希望成員變量 x 和參數 x 具有相同的名稱,則可以使用。米_對於下一個維護你的代碼的人來說會更容易。
什麼是氣泡: ?
還有另一個命名空間你大多不需要這將說明為什麼我說隱藏列表中的 DefineClass() 原型看起來很多類似實例——類名是一個命名空間。 使用氣泡:m_半徑將訪問原型的 m_radius,即使是從實例方法。 如果你認為你需要一個靜態成員變量,這是一種製作靜態成員變量的方法......如果你小心的話。
使用靜態值的原型
下一個示例使用靜態 m_ID 變量。 正如評論所暗示的那樣,我可能應該做出不同的變化,但是這個仍然有用,因為它解釋了“如果你小心的話”警告。 發生的事情是這樣的(再次是我的思維模型):
當下面的 _init_() 運行時, bubble2 類已經將所有原型內容複製到新實例中。 新實例具有原型 m_id 的副本。 _init_() 然後更改原型中的 m_id()。 下一個實例將獲取更改後的值。 其他成員函數必須在原型中的 m_id (bubble2:m_id) 和 this:m_id (或者只是沒有命名空間的 m_id)之間進行選擇。 在這裡,他們使用 m_id,它是實例唯一整數的副本。
在視頻中,最後一塊拼圖在 5 點 15 分出現在屏幕底部邊緣。 黑色圓圈是顯示其 m_id 值的 bubble2。 他們使用 m_id 確保在研究所有近鄰時忽略自己。
// 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 );
);
上面的兩個示例都可以輕鬆地(也許更容易)使用數據表的行來表示對象,使用列來表示方法的成員變量和 JSL 用戶函數。 類的使用,尤其是沒有任何子類化的情況下,如果其他人對 JSL 中的類感到不舒服,可能會使其更難遵循您的 JSL。
說到函數,DefineClass 的文檔也提到了它們。 據我所知,它們幾乎沒有任何好處,應該避免。 我認為類的每個實例可能都會獲得每個方法和每個成員變量的單獨副本。 如果您定義一個 Function() 並將其存儲在成員變量中,那麼您只是在製作其他內容來複製該內容(也許)可能位於更全局的命名空間中,並且只有一個副本。 但是,如果只有一個(或很少)實例,並且您確實需要一個除了參數之外不知道任何內容的類函數,那麼也許類中的函數就是您所需要的。
繼續最後一個示例,讓我們進行一些子類化並查看最後一個命名空間,極好的: ,我必須尋找它(請參閱 JSL 中的評論)。
直觀的例子:基類可能是車輛,子類(或派生類)是卡車和汽車。 卡車可能會用知道避開住宅區街道的導航方法來取代基類導航方法。 汽車可能會利用 HOV 車道。 當被告知從 A 導航到 B 時,一系列車輛將執行正確的操作。
Define Class 有一個有趣的論點:基類(...) 。 在下面的例子中,形狀將是基類並且正方形和圓圈將從形狀導出。 該示例創建一個正方形和圓形列表並顯示它們。
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 filled兩個正方形,兩個圓形,兩個輪廓,兩個填充
以下描述基於反複試驗;我相信它足夠正確,可以成為預測某些事物如何運作的有用模型。
什麼是極好的: ?
創建派生類時,JMP 運行到派生類的末尾基類鏈並返回頂部,首先創建基類,並在它們自己的命名空間中。 命名空間在內部鏈接在一起,以便派生類可以通過查找自己的命名空間來引用成員變量,然後沿著命名空間鏈向下到達基類,直到找到該變量。 這極好的:namespace 只是表示在名稱空間鏈中向前跳一次,而不查找當前名稱空間。 這就是為什麼下面的 JSL 說“如果不需要,不要使用 super: 來調用基本方法”;基方法無法訪問派生命名空間,因此它無法調用派生函數。
多重繼承:如果您使用“接口”並避免重複名稱,它可能會起作用。 祝你好運。 我不確定同級基類適合上面模型中的命名空間鏈。
// 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 );
);
關於什麼這?
C++ 有一個名為“this”的值(其他語言使用“self”和“me”),有時對象需要它來引用自身。 與此不同:名稱空間前綴。 我不認為 JSL 類在類中提供了“this”,您可能會想要創建這樣的一個:
x = newObject(myClass(17));
x::self = x;
或類似的東西。 然後 myClass 方法可以使用“self”來執行需要類實例的操作,例如克隆。
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 instance顯示可以發送到類實例的消息的腳本索引
在包含類實例(指向)的類實例中保留成員變量可能會導致內存洩漏。 這給我們帶來了一個新的話題……實際上是話題。
什麼時候刪除實例?
當沒有對實例的引用時,該實例將被刪除。 在上面的部分中,實例內的“self”引用將阻止實例被刪除,即使您丟失了該實例的所有句柄。 除了關閉 JMP 之外,沒有其他方法可以清理它。
什麼時候複製實例?
這是最好的部分:只有使用 <這意味著實例是通過引用傳遞的。耶! 創建一個簡單的類來包裝大型矩陣並將該類的實例傳遞給用戶函數,而不是讓 JMP 將矩陣參數的副本複製到參數值中,並可能返回另一個副本,這樣的方式就不那麼笨拙。