다음은 대부분 옳습니다. 내가 놓친 것이 있거나 잘못 이해한 것이 있을 수 있습니다. 링크된 문서를 읽고(너무 짧음) 댓글을 달아주세요. 감사합니다.
나쁜 비유 : 클래스는 쿠키 커터입니다. 인스턴스는 쿠키 커터로 만든 쿠키입니다.
비유의 문제 : JSL에도 전화하겠습니다. 수업 ㅏ 원기 . 프로토타입은 실제 쿠키입니다. 프로토타입 쿠키 ~할 수 있었다 먹거나 개조할 수 있지만 일반적으로 그렇게 하고 싶지는 않을 것입니다. 대신 윤곽선을 쿠키 반죽에 대고 가위로 잘라 새로운 쿠키 인스턴스를 만들어야 합니다. 그러나 프로토타입 쿠키를 한 입 베어 물면 이후의 모든 쿠키 인스턴스도 물린 것처럼 보일 것입니다(두 번째 예). 또한 프로토타입 쿠키에 대해 _init_(...) 메서드가 실행되지 않아 반쯤 구워졌을 수 있지만 올바른 모양을 가지고 있습니다.
그만큼 선적 서류 비치 용도 주형 오히려 원기 . 저는 템플릿보다 프로토타입을 선호합니다. 프로토타입은 사용 가능한 개체인 반면 템플릿은 스프레이 페인트가 어디로 가야 하는지 보여줍니다. 이 미묘한 구분은 첫 번째 예에서는 중요하지 않습니다.
간단한 예
다음은 간단한 단일 클래스 예제입니다. 거품 . 클래스 프로토타입은 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_() 메서드 할당 중 하나에서. 그만큼 이것: namespace는 "현재 인스턴스의 멤버 변수"를 의미합니다. 그래서 이것:x = x; 멤버 변수 x와 매개변수 x가 같은 이름을 갖도록 하려는 경우에 사용할 수 있습니다. 중_ 코드를 유지 관리하는 다음 사람이 더 쉬울 것입니다.
뭐야 거품: ?
다른 네임스페이스가 있습니다. 대부분 필요하지 않은 내가 왜 숨겨진 목록에서 DefineClass() 프로토타입이 보이는지 보여줄 것입니다. 많이 like instance--클래스 이름 ~이다 네임스페이스. 사용 거품:m_radius 인스턴스 메서드에서도 프로토타입의 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 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 filled사각형 2개, 원 2개, 윤곽선 2개, 채움 2개
다음 설명은 시행 착오를 기반으로 합니다. 어떻게 작동할지 예측하는 데 도움이 되는 모델이 되기에 충분히 정확하다고 생각합니다.
뭐야 감독자: ?
파생 클래스가 생성되면 JMP는 해당 클래스가 끝날 때까지 실행됩니다. 기본 클래스 기본 클래스를 먼저 만들고 자체 네임스페이스에서 만들어 맨 위로 돌아가 작동합니다. 네임스페이스는 내부적으로 서로 연결되어 파생 클래스가 자체 네임스페이스를 찾은 다음 변수를 찾을 때까지 네임스페이스 체인을 따라 기본 클래스까지 내려감으로써 멤버 변수를 참조할 수 있습니다. 그만큼 감독자 : 네임스페이스는 현재 네임스페이스를 보지 않고 네임스페이스 체인에서 한 번 건너뛰는 것을 의미합니다. 그렇기 때문에 아래 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 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 instance클래스 인스턴스로 보낼 수 있는 메시지를 보여주는 스크립팅 색인
클래스 인스턴스를 포함하는 클래스 인스턴스에 멤버 변수를 유지하면 메모리 누수가 발생할 수 있습니다. 이것은 우리를 새로운 주제로 인도합니다. 사실 주제입니다.
인스턴스는 언제 삭제됩니까?
인스턴스에 대한 참조가 없으면 인스턴스가 삭제됩니다. 위 섹션에서 인스턴스 내부의 "self" 참조는 인스턴스가 삭제되는 것을 방지합니다. 인스턴스에 대한 모든 핸들을 잃어버린 경우에도 . JMP를 닫는 것 외에는 정리할 방법이 없습니다.
인스턴스는 언제 복사됩니까?
가장 중요한 부분은 <이는 인스턴스가 참조로 전달됨을 의미합니다.예이! JMP가 행렬 인수의 복사본을 매개변수 값으로 만들고 다른 복사본을 반환하도록 하는 대신 큰 행렬을 래핑하고 클래스의 인스턴스를 사용자 함수에 전달하는 간단한 클래스를 만드는 것이 덜 어색합니다.