⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 oop.htm

📁 strongForth: a strongly typed dialect of Forth implemented in ANS Forth.
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<kbd>JOURNAL</kbd>'s version were an extended version of 
<kbd>MEDIUM</kbd>'s version, <kbd>[PARENT]</kbd> could be applied as well, 
for example like this:</p>
<pre>:NONAME ( JOURNAL -- )
  DUP [PARENT] SALE
  DUP PRICE @ 100 MAX SWAP PRICE ! ; IS SALE</pre>
<p>This definition works as expected even though the grandparent and not 
the parent of class <kbd>JOURNAL</kbd> defines the original version of 
<kbd>SALE</kbd>. The parent <kbd>PAPER-MEDIUM</kbd> has inherited the 
version from <kbd>JOURNAL</kbd>'s grandparent 
<kbd>MEDIUM</kbd>. If for whatever reason you want to compile 
a version that is different from that of the parent class, you can use 
<kbd>[BIND]</kbd> instead of <kbd>[PARENT]</kbd>:</p>
<pre>[BIND] MEDIUM SALE</pre>
<p><kbd>[BIND]</kbd> allows you to specify the direct parent class as well 
as any indirect parent class whose version of the virtual member word shall 
be compiled with static binding. Specifying any other than direct or indirect 
parent classes is possible, but will cause an ambiguous condition in most 
cases. <kbd>[BIND]</kbd> is actually 
a generalized version of <kbd>[PARENT]</kbd>. Note that the usage of 
<kbd>[PARENT]</kbd> and <kbd>[BIND]</kbd> is not restricted to extending the 
semantics of virtual members within a class hierarchy. You can even chose to 
statically bind a virtual member in the definition of a non-member word like 
<kbd>SELLOUT</kbd>. For example, If you want to display only the title and 
the original price of a medium, you can statically bind <kbd>.</kbd> to 
class <kbd>MEDIUM</kbd> in the definition of <kbd>SELLOUT</kbd>:</p>
<pre><u>: SELLOUT ( MEDIUM -- )</u>
<u>  ." Save money now!" CR DUP [BIND] MEDIUM . CR DUP SALE</u>
<u>  ." Now for only $" .PRICE ." !" ;</u>  OK
<u>1999 BOOK1 SET-PRICE</u>  OK
<u>BOOK1 SELLOUT</u> Save money now!
Starting Forth ($19.99)
Now for only $15.99! OK
<u>799 JOURNAL1 SET-PRICE</u>  OK
<u>JOURNAL1 SELLOUT</u> Save money now!
Scientific American ($7.99)
Now for only $1.00! OK</pre>
<p>Members that have been compiled into the <kbd>PROTECTED</kbd> word list 
of a class are passed on to child classes as well. 
However, private members can only be directly referred to within the 
parent class definition. Accessing private data members or private member words 
within the child class definitions or outside of a class definition can only 
happen indirectly through public or protected member words. That's because the 
<kbd>PRIVATE</kbd> word list of a class is not passed on to its children. The 
<kbd>PROTECTED</kbd> word list of a class, on the other hand, is passed on to 
all its children. Each child class actually starts with the <kbd>PROTECTED</kbd> 
word list of its parent class and extends it with its own protected members, 
whereas a child's <kbd>PRIVATE</kbd> word list is initially empty. Given the 
parent class definition</p>
<pre>DT OBJECT PROCREATES PARENT-CLASS
DT PARENT-CLASS PROCREATES CHILD-CLASS

CLASS PARENT-CLASS
BODY
  NULL UNSIGNED MEMBER PUBLIC-DATA-MEMBER
  :MEMBER PUBLIC-MEMBER-WORD ( PARENT-CLASS -- )
    >THIS ;
  ALSO PRIVATE DEFINITIONS
  NULL UNSIGNED MEMBER PRIVATE-DATA-MEMBER
  :MEMBER PRIVATE-MEMBER-WORD ( PARENT-CLASS -- )
    >THIS ;
  ALSO PROTECTED DEFINITIONS
  NULL UNSIGNED MEMBER PROTECTED-DATA-MEMBER
  :MEMBER PROTECTED-MEMBER-WORD ( PARENT-CLASS -- )
    >THIS ;
ENDCLASS</pre>
<p>here's what happens in the child class definition:</p>
<pre><u>CLASS CHILD-CLASS BODY</u>  OK
<u>ALSO PRIVATE WORDS</u>  OK
<u>ALSO PROTECTED WORDS</u>
PROTECTED-MEMBER-WORD ( PARENT-CLASS -- )
PROTECTED-DATA-MEMBER ( PARENT-CLASS -- ADDRESS -> UNSIGNED )  OK</pre>
<p>Note that the assignment of a virtual member word does not affect the 
word list in which the virtual member word had been originally defined with 
<kbd>VIRTUAL</kbd>.</p>
<h2><kbd>NEW</kbd> and <kbd>DELETE</kbd></h2>
<p>By default, new structures and new objects are allocated in dynamic memory. 
<kbd>NEW</kbd> is a state-smart immediate word that executes or compiles the 
word <kbd>(NEW)</kbd> in order to allocate and initialize the new structure 
or object. It determines the data type of the structure or object by parsing 
the input stream for the name of the data type. If the data type is a structure, 
<kbd>(NEW)</kbd> is passed a literal parameter of data type 
<kbd>ADDRESS -> STRUCTURE</kbd> which is the address of a cell that contains the 
size of the structure in address units. <kbd>STRUCTURE</kbd> is the actual data 
type of the structure. The output parameter of <kbd>(NEW)</kbd> is the address 
of the allocated memory as an item of the structure's data type.</p>
<pre>(NEW) ( ADDRESS -> STRUCTURE -- 2ND )</pre>
<p>If you prefer to do the memory allocation yourself, all 
you have to do is pushing the address of the allocated memory onto the stack 
before <kbd>NEW</kbd> gets executed. This works because <kbd>(NEW)</kbd> is 
overloaded with two additional versions that expect addresses of data types 
<kbd>ADDRESS</kbd> and <kbd>CADDRESS</kbd> on the stack:</p>
<pre>(NEW) ( ADDRESS ADDRESS -> STRUCTURE -- 3RD )
(NEW) ( CADDRESS ADDRESS -> STRUCTURE -- 3RD )</pre>
<p>Let's assume you want to statically allocate a structure in the data space 
using <kbd>ALLOT</kbd>. Here's what you have to do:</p>
<pre>HERE DT structure SIZE-STRUCTURE ALLOT NEW structure</pre>
<p><kbd>structure</kbd> stands for the name of structure. Remember that 
new structures are not being automatically initialized.</p>
<p>You can even chose to implement your own version of <kbd>(NEW)</kbd> for 
allocating structures. For example, if you generally want to allocate structures with 
<kbd>ALLOT</kbd> instead of with <kbd>ALLOCATE</kbd>, the following version of 
<kbd>(NEW)</kbd> does the job. If you define a separate vocabulary for it, you 
can even switch arbitrarily between dynamic and static allocation:</p>
<pre><u>VOCABULARY STATIC-ALLOCATION</u>  OK
<u>GET-CURRENT ALSO STATIC-ALLOCATION DEFINITIONS</u>  OK
<u>: (NEW) ( ADDRESS -> STRUCTURE -- 2ND )</u>
<u>  SIZE-STRUCTURE HERE CAST STRUCTURE SWAP ALLOT ;</u>  OK
<u>SET-CURRENT HERE .</u> 4756966  OK
<u>NEW RECTANGLE .S .</u> RECTANGLE 4756966  OK
<u>PREVIOUS</u>  OK
<u>NEW RECTANGLE DUP .</u> 1525264  OK
<u>DELETE</u>  OK</pre>
<p>A structure that is no longer required shall be deleted with 
<kbd>DELETE</kbd>. <kbd>DELETE</kbd> simply frees the allocated dynamic 
memory:</p>
<pre>: DELETE ( STRUCTURE -- )
  CAST ADDRESS FREE THROW ;</pre>
<p>However, bear in mind that <kbd>DELETE</kbd> must not be applied to 
structures that were not allocated in dynamic memory with the first version 
of <kbd>(NEW)</kbd>.</p>
<p>Allocating and deleting objects is similar to allocating and deleting 
structures. The main differences are that each object has a constructor that 
needs to be executed immediately <em>after</em> the memory space for the 
object has been allocated, and a destructor that is exectured immediately 
<em>before</em> the memory space for the object is released. Furthermore, the 
virtual member table pointer needs to be stored into the first cell of a new 
object. Since <kbd>NEW</kbd> is used both for creating new structures and 
new objects, corresponding versions of <kbd>(NEW)</kbd> are provided:</p>
<pre>: (NEW) ( ADDRESS -> OBJECT -- 2ND )
  DUP SIZE-OBJECT ALLOCATE THROW
  TUCK -> ADDRESS -> OBJECT ! CAST OBJECT ;

: (NEW) ( ADDRESS ADDRESS -> OBJECT -- 3RD )
  OVER -> ADDRESS -> OBJECT ! CAST OBJECT ;

: (NEW) ( CDATA CONST -> OBJECT -- 3RD )
  OVER -> ADDRESS -> OBJECT ! CAST OBJECT ;</pre>
<p>The input parameter <kbd>ADDRESS -> OBJECT</kbd> is the pointer to the 
object's virtual member table, whose first cell contains the size of the 
object in address units. The actual definitions of <kbd>(NEW)</kbd> 
are slightly different than what is shown here, but this has no impact on 
the semantics. Of course, you can also define your own versions of 
<kbd>(NEW)</kbd> just as has been demonstrated for structures a few 
paragraphs above.</p>
<p>Now, what about the constructors? Since the constructors 
of a class always have the same name as the class, and <kbd>NEW</kbd> parses 
the class name, <kbd>NEW</kbd> simply saves the input source specification 
before parsing, and restores it after parsing. The result is that the 
class name is evaluated immediately after <kbd>NEW</kbd>, executing or 
compiling a constructor that matches the parameters on the stack. You can 
define multiple constructors for different sets of parameters. For example,
the <kbd>STRING</kbd> class that was shown above has a constructor that 
expects the address and count of a character string in addition to the 
string object. However, a string can also be initialized with another object 
of class <kbd>STRING</kbd>, or with just a character count. An example of an 
extended version of the <kbd>STRING</kbd> class with additional constructors 
will be shown later in this section.</p>
<p>Since <kbd>NEW</kbd> always evaluates the name of a constructor, it is 
not possible to create an object of a class that has no constructor. However, 
defining a class without a constructor can make sense, if the only purpose of 
this class is to derive child classes from it. Another interesting technique is 
to define the constructors of a class in the <kbd>PRIVATE</kbd> word list. 
The result is that objects of this class can only be created by member words 
of classes that have been declared friends of the class. Objects of classes 
whose constructors were defined in the <kbd>PROTECTED</kbd> word list can 
only be created by member words of child classes or friend classes.</p>
<p>In contrast to constructors, each class has only one destructor, because 
destructors do not have parameters in addition to the object itself. Moreover, 
all destructors are virtual members and share the common name 
<kbd>DESTRUCTOR</kbd>. They have one input parameter of the class data type 
that is not consumed. <kbd>DELETE</kbd> for objects is an immediate word 
that evaluates first the destructor and then a word called 
<kbd>(DELETE)</kbd> that releases the allocated memory space:</p>
<pre>: (DELETE) ( OBJECT -- )
  CAST ADDRESS FREE THROW ;

: DELETE ( -- )
  " DESTRUCTOR" EVALUATE POSTPONE (DELETE) ; IMMEDIATE</pre>
<p>If an object has not been allocated in the dynamic memory space using the 
first version of <kbd>(NEW)</kbd>, you may not apply <kbd>DELETE</kbd> or 
<kbd>(DELETE)</kbd> to it. If you want to destroy the object anyway, you have 
to use its destructor alone.</p>
<p>Now what's the typical semantic of a destructor? The destructor of class 
<kbd>OBJECT</kbd> does nothing:</p>
<pre>:NONAME ( OBJECT -- 1ST ) ; IS DESTRUCTOR</pre>
<p>But the destructor of the <kbd>STRING</kbd> class actually needs a 
destructor that frees the dynamic memory space the constructor allocated for 
the character array. Otherwise, each time an object of class <kbd>STRING</kbd> 
is deleted, the available dynamic memory space shrinks by the the size of the 
character array. Without a dedicated destructor the definition of the 
<kbd>STRING</kbd> class is incomplete. It would just inherit the default 
destructor from class <kbd>OBJECT</kbd>. Adding the destructor and some more 
constructors, the definition of the <kbd>STRING</kbd> class now looks like 
this:</p>
<pre>DT OBJECT PROCREATES STRING

CLASS STRING
BODY
  ALSO PROTECTED DEFINITIONS
  NULL UNSIGNED MEMBER LEN
  NULL CADDRESS -> CHARACTER MEMBER BUF
  :MEMBER INIT ( UNSIGNED STRING -- )
    >THIS DUP LEN ! CALLOCATE THROW -> CHARACTER BUF ! ;
  ALSO FORTH DEFINITIONS PREVIOUS
  :MEMBER STRING ( UNSIGNED STRING -- 2ND )
    >THIS INIT BUF @ LEN @ BLANK THIS ;
  :MEMBER STRING ( CADDRESS -> CHARACTER UNSIGNED STRING -- 4 TH )
    >THIS INIT BUF @ LEN @ MOVE THIS ;
  :MEMBER STRING ( STRING STRING -- 2ND )
    >THIS DUP LEN @ INIT BUF @ BUF @ LEN @ MOVE THIS ;
  :MEMBER . ( STRING -- )
    >THIS THIS
    IF LEN @
       IF BUF @ LEN @ TYPE
       ELSE ." &lt;empty>"
       THEN
    ELSE ." &lt;null>" 
    THEN SPACE ;
  :MEMBER LENGTH ( STRING -- UNSIGNED )
    LEN @ ;
  :NONAME ( STRING -- 1ST )
    DUP BUF @ FREE THROW ; IS DESTRUCTOR
  ENDCLASS</pre>
<p>Note that <kbd>INIT</kbd> has been made a protected member, because it is 
supposed to be used only by the constructors of the <kbd>STRING</kbd> class 
and by its children.</p>
<p>Finally, here's another interesting feature that can be applied to both 
structures and objects. You can define dedicated versions of <kbd>(NEW)</kbd> 
and <kbd>(DELETE)</kbd> that only apply to a specific object, or dedicated 
versions of <kbd>(NEW)</kbd> and <kbd>DELETE</kbd> for specific structures. 
All you have to do is overloading <kbd>(NEW)</kbd> and <kbd>(DELETE)</kbd> 
for the specific data type. But what's this feature good for? One example 
is if you want to allocate all objects of a certain class in the data space 
instead of in dynamic memory, while the default allocation for all other 
objects remains dynamic:</p>
<pre>: (NEW) ( ADDRESS -> SAMPLE-CLASS -- 2ND )
  SIZE-OBJECT HERE CAST SAMPLE-CLASS SWAP ALLOT ;</pre>
<p>This definition of <kbd>(NEW)</kbd> overloads the default version and is 
only invoked for the class <kbd>SAMPLE-CLASS</kbd> and its children. Since 
the allocation is static, you don't need to overload <kbd>(DELETE)</kbd>. The 
overloaded version of <kbd>(NEW)</kbd> can be either a member word or a global 
definition.</p>
<p>As anoth

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -