📄 oop.htm
字号:
is a <em>friend</em> of another class can access its private and protected
members, just as if these members were defined in the friend class itself.
Within the definition of a class <kbd>A</kbd>, a list of classes
<kbd>B1, B2, ..., Bn</kbd> can be granted access to the private and protected
members of class <kbd>A</kbd> with the phrase:</p>
<pre>FRIENDS( class-B1 class-B2 ... class-Bn )</pre>
<p>Within each of the classes <kbd>B1, B2, ..., Bn</kbd>, you can then add
the combined <kbd>PRIVATE</kbd> and <kbd>PROTECTED</kbd> word list of class
<kbd>A</kbd> to the search order with the phrase</p>
<pre>ALSO ACCESS class-A</pre>
<p><kbd>ACCESS class-A</kbd> has a similar semantic like a vocabulary.
<kbd>class-A</kbd>, <kbd>class-B1</kbd>, <kbd>class-B2</kbd>, ...,
<kbd>class-Bn</kbd> are the actual class names. Note that only classes can be
declared friends of a class. It is not possible, like in C++, to declare a
word a friend to a class.</p>
<p>A typical application that takes advantage of the friendship mechanism is
an iterator class. An iterator is a class that provides iterative access to
some items that belong to another class. The iterator contains a member word
that returns the <em>next</em> item of the other class each time it is
executed. In the following example,
an iterator is defined for a (simplified) <kbd>STRING</kbd> class. The member
word <kbd>NEXT</kbd> of the iterator returns one character of the string after
the other, starting with the first one:</p>
<pre>DT OBJECT PROCREATES STRING
DT OBJECT PROCREATES STRING-ITERATOR
CLASS STRING
BODY
FRIENDS( STRING-ITERATOR )
ALSO PROTECTED DEFINITIONS
NULL UNSIGNED MEMBER LEN
NULL CADDRESS -> CHARACTER MEMBER BUF
ALSO FORTH DEFINITIONS PREVIOUS
:MEMBER STRING ( CADDRESS -> CHARACTER UNSIGNED STRING -- 4 TH )
>THIS DUP LEN ! CALLOCATE THROW -> CHARACTER BUF !
BUF @ LEN @ MOVE THIS ;
:MEMBER . ( STRING -- )
>THIS THIS
IF LEN @
IF BUF @ LEN @ TYPE
ELSE ." <empty>"
THEN
ELSE ." <null>"
THEN SPACE ;
:MEMBER LENGTH ( STRING -- UNSIGNED )
LEN @ ;
ENDCLASS
CLASS STRING-ITERATOR
BODY
ALSO ACCESS STRING
ALSO PROTECTED DEFINITIONS
NULL STRING MEMBER STRI
NULL UNSIGNED MEMBER INDX
ALSO FORTH DEFINITIONS PREVIOUS
:MEMBER STRING-ITERATOR ( STRING STRING-ITERATOR -- 2ND )
>THIS STRI ! 0 INDX ! THIS ;
:MEMBER NEXT ( STRING-ITERATOR -- CHARACTER )
>THIS INDX @ STRI @ LENGTH <
IF STRI @ BUF @ INDX @ + @ 1 INDX +!
ELSE NULL CHARACTER
THEN ;
ENDCLASS</pre>
<p>Class <kbd>STRING-ITERATOR</kbd> is a friend of class <kbd>STRING</kbd>,
because it needs access to <kbd>STRING</kbd>'s data members. Here's an example
of how the two classes may be used together:</p>
<pre><u>" abc" NEW STRING CONSTANT STRING1</u> OK
<u>" " NEW STRING CONSTANT STRING2</u> OK
<u>STRING1 .</u> abc OK
<u>STRING2 .</u> <empty> OK
<u>NULL STRING .</u> <null> OK
<u>STRING1 LENGTH .</u> 3 OK
<u>STRING2 LENGTH .</u> 0 OK
<u>STRING1 NEW STRING-ITERATOR CONSTANT SI1</u> OK
<u>SI1 NEXT .</u> a OK
<u>SI1 NEXT .</u> b OK
<u>SI1 NEXT .</u> c OK
<u>SI1 NEXT CAST INTEGER .</u> 0 OK
<u>SI1 DELETE</u> OK</pre>
<p>After the iterator has exceeded the end of the string, it is useless and
can be deleted.</p>
<p>StrongForth does not allow class definitions to be nested. In the
above example, the class definition of <kbd>STRING-ITERATOR</kbd> cannot be
enclosed within the class definition of <kbd>STRING</kbd>, although this might
look like a reasonable approach.</p>
<p>The class defnitions of <kbd>STRING</kbd> and <kbd>STRING-ITERATOR</kbd>
contain, just like the last version of the class definition of <kbd>POINT</kbd>,
only data members defined by <kbd>MEMBER</kbd> and <kbd>CMEMBER</kbd>, and
member words defined by <kbd>:MEMBER</kbd>. But you've seen in the first version
of <kbd>POINT</kbd>, that it is also possible to define member words as simple
colon definitions. Now, what happens if you define words with <kbd>VARIABLE</kbd>,
<kbd>CONSTANT</kbd> and <kbd>VALUE</kbd>? These words obviously define
variables, constants and values that are not data members, and that are not
even related to the class they are defined in. Nevertheless, it can make sense
to use these defining words within a class definition, if they are added to
the <kbd>PRIVATE</kbd> or <kbd>PROTECTED</kbd> word lists. Private variables,
constants and values are only available to the members of the class and
to friends of the class. and their names can be reused in other classes. The
following extension of the <kbd>POINT</kbd> class contains both a private
variable and a private constant:</p>
<pre>DT OBJECT PROCREATES POINT
CLASS POINT
BODY
ALSO PRIVATE DEFINITIONS
+0 MEMBER PX
+0 MEMBER PY
0 MEMBER PINDEX
CHAR P CONSTANT ID
0 VARIABLE COUNT
ALSO FORTH DEFINITIONS PREVIOUS
:MEMBER SET-POINT ( SIGNED SIGNED POINT -- )
>THIS PY ! PX ! ;
:MEMBER GET-POINT ( POINT -- SIGNED SIGNED )
>THIS PX @ PY @ ;
:MEMBER POINT ( POINT -- 1ST )
>THIS +0 +0 SET-POINT 1 COUNT +! COUNT @ PINDEX ! THIS ;
:MEMBER .NAME ( POINT -- )
ID . PINDEX @ . ;
ENDCLASS</pre>
<p>Each object of class <kbd>POINT</kbd> is assigned an index <kbd>PINDEX</kbd>.
In order to make sure that the index is unique, the index of a new
<kbd>POINT</kbd> object is taken from a non-member variable <kbd>COUNT</kbd>
that is incremented by the constructor. <kbd>.NAME</kbd> is a (public)
member word that displays the index together with a one-letter identifier that
is specific for points. The identifier is defined as a constant in the
<kbd>PRIVATE</kbd> word list. Here's an example of how this version of
<kbd>POINT</kbd> can be used:</p>
<pre><u>NEW POINT CONSTANT FIRST</u> OK
<u>+3 -8 FIRST SET-POINT</u> OK
<u>NEW POINT CONSTANT SECOND</u> OK
<u>FIRST .NAME FIRST GET-POINT SWAP . .</u> P1 3 -8 OK
<u>SECOND .NAME</u> P2 OK</pre>
<p>Colon definitions defined by <kbd>:</kbd> can in some cases be used as a
replacement for what is called in C++ a <em>static member</em> of the class,
because they don't need to be bound to a specific object. The necessity to
include those words in the class definition might arise from the fact that they
access private or protected non-member variables, constants and values. If
you need to overload colon definitions, you can add an object of the respective
class type as a dummy input parameter. However, please note that such colon
definitions within class definitions are actually not the same as static
members in C++ classes.</p>
<p>Similarly, private constants in StrongForth must not be confused with
<kbd>const</kbd> members in C++. It is not possible to reference a constant
through an object of the class the constant is defined in. Furthermore, there is
nothing like <kbd>const</kbd> classes or <kbd>const</kbd> member words that are
not allowed to change the data members. Of course, you can define a class whose
member words (except for the constructors) do not change the data members, but
there are no means for the compiler to ensure that a class definition really does
not contain non-constant member words.</p>
<h2>Inheritance And Binding</h2>
<p>The concept of inheritance is a fundamental technique of object oriented
programming. You already got a quick glance at inheritance at the end of the
section about structures. Generally, a class whose data type is a direct or
indirect subtype of another class inherits the members from the other class.
It's the same mechanism as for ordinary data types. For example, <kbd>DUP</kbd>
is a word that expects an item of data type <kbd>SINGLE</kbd> on the stacks,
but it can also be applied to all direct or indirect subtypes of
<kbd>SINGLE</kbd>. So, let's design a simple class hierarchy that will serve
as an example:</p>
<pre>DT OBJECT PROCREATES MEDIUM
DT MEDIUM PROCREATES PAPER-MEDIUM
DT MEDIUM PROCREATES ELECTRONIC-MEDIUM
DT PAPER-MEDIUM PROCREATES BOOK
DT PAPER-MEDIUM PROCREATES JOURNAL
DT ELECTRONIC-MEDIUM PROCREATES ANALOG-MEDIUM
DT ELECTRONIC-MEDIUM PROCREATES DIGITAL-MEDIUM
DT DIGITAL-MEDIUM PROCREATES CD
DT DIGITAL-MEDIUM PROCREATES DVD
\ ...</pre>
<p>Class <kbd>MEDIUM</kbd> is at the top of the class hierarchy. Each medium
is supposed to have a title and a price. Here's the corresponding class
definition:</p>
<pre>CLASS MEDIUM
BODY
ALSO PROTECTED DEFINITIONS
NULL STRING MEMBER TITLE
NULL UNSIGNED MEMBER PRICE \ in cent
FORTH DEFINITIONS PROTECTED
:MEMBER MEDIUM ( CADDRESS -> CHARACTER UNSIGNED MEDIUM -- 4 TH )
>THIS NEW STRING TITLE ! 0 PRICE ! THIS ;
:MEMBER SET-PRICE ( UNSIGNED MEDIUM -- )
PRICE ! ;
:MEMBER GET-PRICE ( MEDIUM -- UNSIGNED )
PRICE @ ;
:MEMBER SALE ( MEDIUM -- )
>THIS PRICE @ 8 10 */ PRICE ! ;
:MEMBER .PRICE ( MEDIUM -- )
PRICE @ 100 /MOD 0 .R [CHAR] . . S>D <# # # #> TYPE ;
:MEMBER . ( MEDIUM -- )
>THIS TITLE @ . ." ($" .PRICE ." )" ;
ENDCLASS
</pre>
<p>The data members are protected, whereas the member words including
the constructors are public definitions that can be accessed from outside of
the class definition. Remember that protected members can still be accessed
within the definitions of derived classes.</p>
<p>Since data type <kbd>PAPER-MEDIUM</kbd> is a child of data type
<kbd>MEDIUM</kbd>, it inherits all of <kbd>MEDIUM</kbd>'s data members and
member words. Additionally, it defines the number of pages as a data member
and a member word that returns the number of pages. Its constructor reuses
the constructor of <kbd>MEDIUM</kbd> and additionally initializes the number
of pages:</p>
<pre>CLASS PAPER-MEDIUM
BODY
ALSO PROTECTED DEFINITIONS
NULL UNSIGNED MEMBER #PAGES
FORTH DEFINITIONS PROTECTED
:MEMBER PAPER-MEDIUM ( CADDRESS -> CHARACTER UNSIGNED UNSIGNED
PAPER-MEDIUM -- 5 TH )
>THIS #PAGES ! MEDIUM ;
:MEMBER PAGES ( PAPER-MEDIUM -- UNSIGNED )
#PAGES @ ;
:MEMBER . ( PAPER-MEDIUM -- )
DUP . CR PAGES . ." pages" ;
ENDCLASS</pre>
<p>Finally, here are the definitions of the <kbd>BOOK</kbd> and
<kbd>JORUNAL</kbd> classes, which are both derived from
<kbd>PAPER-MEDIUM</kbd>. The other classes (<kbd>ELECTRONIC-MEDIUM</kbd> and
its derived classes) are not required for this example.</p>
<pre>CLASS BOOK
BODY
ALSO PROTECTED DEFINITIONS
NULL STRING MEMBER AUTHOR
FORTH DEFINITIONS PROTECTED
:MEMBER BOOK ( CADDRESS -> CHARACTER UNSIGNED UNSIGNED BOOK -- 5 TH )
>THIS NULL STRING AUTHOR ! PAPER-MEDIUM ;
:MEMBER SET-AUTHOR ( CADDRESS -> CHARACTER UNSIGNED BOOK -- )
>THIS NEW STRING AUTHOR ! ;
:MEMBER GET-AUTHOR ( BOOK -- STRING )
AUTHOR @ ;
:MEMBER . ( BOOK -- )
DUP GET-AUTHOR . ." - " . ;
ENDCLASS
CLASS JOURNAL
BODY
ALSO PROTECTED DEFINITIONS
NULL UNSIGNED MEMBER YEAR
NULL UNSIGNED MEMBER MONTH
FORTH DEFINITIONS PROTECTED
:MEMBER JOURNAL ( CADDRESS -> CHARACTER UNSIGNED UNSIGNED UNSIGNED
UNSIGNED JOURNAL -- 7 TH )
>THIS YEAR ! MONTH ! PAPER-MEDIUM ;
:MEMBER SALE ( JOURNAL -- )
100 SWAP PRICE ! ;
:MEMBER .EDITION ( JOURNAL -- )
DUP MONTH @ 0 .R [CHAR] / . YEAR @ . ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -