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

📄 oop.htm

📁 strongForth: a strongly typed dialect of Forth implemented in ANS Forth.
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<html>
<head>
<title>Object Oriented Programming</title>
</head>
<body>
<h1>Object Oriented Programming</h1>
<p>A library for data structures and object oriented programming is available for 
StrongForth.f. It is mainly based on the C++ model 
of object oriented programming, providing similar features and using the same 
terminology. It fully supports polymorphism, encapsulation and inheritance. Objects 
are actually special data types that can be passed on the stack and that are 
consumed by member functions. Other important features and properties are:</p>
<ul>
 <li>early and late binding,</li>
 <li>single inheritance for code and data,</li>
 <li>static, dynamic and class specific memory allocation,</li>
 <li>explicit constructors, and</li>
 <li>full support for bit fields.</li>
</ul>
<p>Multiple class inheritance is not supported. Furthermore, all kinds of 
implicit data type conversions and default actions have been omitted. Implicit data 
type conversions are dangerous anyway, because they are somtimes ambiguous and 
can lead to unexpected results. Anyway, StrongForth's hierarchical data type 
system often makes type conversions obsolete, because words that expect items of 
a specific data type can generally be applied to all subtypes of it.</p>
<p>Object oriented programming can be made available by first including the 
<em>Memory-Allocation</em> word set, and then including the object oriented 
programming library:</p>
<pre>" memory.sf" INCLUDE
" OOP.sf" INCLUDE
</pre>
<p>Data structures are classes without dedicated member functions. They are actually 
simplified kinds of classes. That's why we'll start with data structures as an 
introduction to the object oriented programming library.</p>
<h2>Structures</h2>
<p>Data structures are a pretty common feature of high-level programming languages. 
A data structure consists of a set of data members that can be accessed in predefined 
ways. For example, consider a data structure that describes a rectangle on the 
screen. A very simple version might consist of its width and its height, plus the 
coordinates of its lower left corner.</p>
<p>There are numerous ways to implement data structures 
in ANS Forth. In StrongForth, the data type system makes the implementation a little 
bit more challenging, because each structure and each of its members has to have a 
data type. As a reward, StrongForth's structures are type-save. You can only store data 
of the specified type in a data member, and you cannot access members that do not 
exist in a structure, unless you use an explicit type cast. Furthermore, there are no 
name conflicts between members of different structures. You can overload members as 
often as you like without any risk of accessing a member of the wrong structure.</p>
<p>Here's a first example of a simple structure definition and how it can be used:</p>
<pre>DT STRUCTURE PROCREATES RECTANGLE

STRUCT RECTANGLE
  NULL SIGNED MEMBER PX
  NULL SIGNED MEMBER PY
  NULL UNSIGNED MEMBER WIDTH
  NULL UNSIGNED MEMBER HEIGHT
ENDSTRUCT

NEW RECTANGLE CONSTANT RECT1
+100 RECT1 PX !
+150 RECT1 PY !
  40 RECT1 WIDTH !
  25 RECT1 HEIGHT !</pre>
<p>Data type <kbd>STRUCTURE</kbd> is a direct subtype of data type <kbd>SINGLE</kbd>. 
Each new type of structure has its own data type that has to be directly or indirectly 
derived from <kbd>STRUCTURE</kbd>. An extended version of <kbd>PROCREATES</kbd> 
reserves memory space for specific attributes of data types that are derived from 
<kbd>STRUCTURE</kbd>. The fact that each kind of structure is a unique data type 
enables the interpreter and the compiler to perform the necessary type checks and to 
ensure that only data members that are actually included in a given structure can be 
accessed.</p>
<p>Once a new data type has been created, the data members can be defined between 
<kbd>STRUCT</kbd> and <kbd>ENDSTRUCT</kbd>. <kbd>STRUCT</kbd> checks whether the 
given data type was really derived from data type <kbd>STRUCTURE</kbd> and leaves 
an item of data type <kbd>STRUCT-SIZE</kbd> on the stack, which counts the 
size of the structure bits. It is incremented each time a new 
data member is added to the structure. At the end of the structure definition, 
<kbd>ENDSTRUCT</kbd> stores the accumulated size of the data structure as an 
attribute of the structure's data type. The data type of the currently defined 
structure (<kbd>RECTANGLE</kbd>) is stored in the global variable 
<kbd>THIS-CLASS</kbd> to be readily available whenever it's needed.</p>
<p>The creation of a new data type for the structure is decoupled from the structure 
definition. I. e., you first have to create a new data type that is directly or 
indirectly derived from data type <kbd>STRUCTURE</kbd>, and then you can specify 
the members of the structure. This decoupling makes it possible to define members 
of the structure data type itself, for example if a structure shall contain a 
pointer to another structure of the same type. Furthermore, cross references 
between two structures can be implemented easily, like in this example:</p>
<pre>DT STRUCTURE PROCREATES STRUCT-A
DT STRUCTURE PROCREATES STRUCT-B

STRUCT STRUCT-A
  NULL STRUCT-B MEMBER SB
  \ ... \
ENDSTRUCT

STRUCT STRUCT-B
  NULL STRUCT-A MEMBER SA
  \ ... \
ENDSTRUCT</pre>
<p><kbd>MEMBER</kbd> is a defining word that defines the data members of the 
structure. In the above example, the data members are <kbd>PX</kbd>, <kbd>PY</kbd>, 
<kbd>WIDTH</kbd> and <kbd>HEIGHT</kbd>:</p>
<pre>PX ( RECTANGLE -- ADDRESS -> SIGNED )
PY ( RECTANGLE -- ADDRESS -> SIGNED )
WIDTH ( RECTANGLE -- ADDRESS -> UNSIGNED )
HEIGHT ( RECTANGLE -- ADDRESS -> UNSIGNED )</pre>
<p><kbd>MEMBER</kbd> expects the current size 
of the structure in bits, which is originally supplied by <kbd>STRUCT</kbd>, plus 
a dummy parameter that has the data type of the new member. A member definition 
looks like an ordinary variable definition. But since the data member is not being 
initialized, a null item can be provided as a sample for the data type. The 
execution semantic of a data member is to return its address within a specific 
instance of the structure. StrongForth does not provide defining words for data 
members that behave like values.</p>
<p>Structure <kbd>RECT1</kbd> of the example may thus be used as follows:</p>
<pre><u>40 RECT1 .S</u> UNSIGNED RECTANGLE  OK
<u>WIDTH .S !</u> UNSIGNED ADDRESS -> UNSIGNED  OK
<u>25 RECT1 HEIGHT !</u>  OK
<u>RECT1 WIDTH @ .</u> 40  OK</pre>
<p><kbd>NEW</kbd> allocates dynamic memory for a structure of a given type. The 
new instance of the structure may be stored as a constant, as in this example. 
<kbd>PX</kbd>, <kbd>PY</kbd>, <kbd>WIDTH</kbd> and <kbd>HEIGHT</kbd> can then be 
used to access the data members of the structure.</p>
<p>Of course, data members need not be all single-cell items. It is also 
possible to define double-cell items and character size 
items as members, or even arrays of items with the same data type. Here's a 
more comprehensive example:</p>
<pre><u>DT STRUCTURE PROCREATES HEADER</u>  OK</u>
<u>STRUCT HEADER</u>  OK
<u>  NULL UNSIGNED CMEMBER WLENGTH</u>  OK
<u>  NULL CHARACTER 31 CMEMBERS WNAME ALIGNED</u>  OK
<u>  NULL ADDRESS MEMBER WLINK</u>  OK
<u>  NULL LOGICAL MEMBER ATTRIBUTES</u>  OK
<u>  NULL TOKEN MEMBER CODEFIELD</u>  OK
<u>  NULL DATA-TYPE 8 MEMBERS PARAMETERS</u>  OK
<u>ENDSTRUCT</u>  OK
<u>NEW HEADER CONSTANT WORD1</u>  OK
<u>" TEST" DUP WORD1 WLENGTH .S !</u> CADDRESS -> CHARACTER UNSIGNED UNSIGNED CADDRESS -> UNSIGNED  OK
<u>WORD1 WNAME SWAP .S MOVE</u> CADDRESS -> CHARACTER CADDRESS -> CHARACTER UNSIGNED  OK
<u>DICT-HERE WORD1 WLINK .S !</u> ADDRESS ADDRESS -> ADDRESS  OK
<u>'HOST 2/ WORD1 CODEFIELD .S !</u> TOKEN ADDRESS -> TOKEN  OK
<u>2 CAST LOGICAL WORD1 ATTRIBUTES .S !</u> LOGICAL ADDRESS -> LOGICAL  OK
<u>DT SIGNED DT-INPUT OR WORD1 PARAMETERS .S !</u> DATA-TYPE ADDRESS -> DATA-TYPE  OK
<u>DT SIGNED DT-OUTPUT OR 1 OFFSET+ WORD1 PARAMETERS 1+ .S !</u> DATA-TYPE ADDRESS -> DATA-TYPE  OK
<u>WORD1 WNAME WORD1 WLENGTH @ .S</u> CADDRESS -> CHARACTER UNSIGNED  OK
<u>TYPE</u> TEST OK</pre>
<p><kbd>CMEMBER</kbd> defines a character size data member, whose address is of 
data type <kbd>CADDRESS -> ...</kbd>. Of course, defining character size members 
can lead to the following members becoming unaligned. <kbd>ALIGNED</kbd> is used 
after the second character size member to re-align the offset. Since the already 
existing version of <kbd>ALIGNED</kbd> only works for addresses, an overloaded 
version for items of data type <kbd>STRUCT-SIZE</kbd> has to be provided:</p>
<pre>ALIGNED ( STRUCT-SIZE -- 1ST )</pre>
<p>Arrays of data members can easily be defined with <kbd>MEMBERS</kbd>, 
<kbd>CMEMBERS</kbd> etc. These defining words expect an additional size parameter 
on the stack. Their runtime semantics is to return the address of the first 
array element. Here's a list of all defining words for data members:</p>
<pre>MEMBER ( STRUCT-SIZE SINGLE -- 1ST ) 
MEMBER ( STRUCT-SIZE DOUBLE -- 1ST ) 
CMEMBER ( STRUCT-SIZE SINGLE -- 1ST ) 

MEMBERS ( STRUCT-SIZE SINGLE UNSIGNED -- 1ST ) 
MEMBERS ( STRUCT-SIZE DOUBLE UNSIGNED -- 1ST ) 
CMEMBERS ( STRUCT-SIZE SINGLE UNSIGNED -- 1ST )</pre>
<p>In connection with structures and classes, overloading becomes once 
more a very useful feature, because the names of data members can be reused for different 
structures and classes. Since the input parameter of member definitions like 
<kbd>PX</kbd> has the data type of the structure it belongs to, data members from 
different structures do never interfere, even if they have the same name. The 
interpreter and the compiler are always able to chose the correct version.</p>
<p>New instances of structures can be dynamically allocated with <kbd>NEW</kbd>. 
To free the dynamic memory space occupied by a structure, you should use 
<kbd>DELETE</kbd>:</p>
<pre><u>RECT1 DELETE</u>  OK</pre>
<p>If you prefer to allocate static memory space or to use any other place for the 
structure's data members, you simply provide <kbd>NEW</kbd> with the address as 
an additional parameter of data type <kbd>ADDRESS</kbd> or <kbd>CADDRESS</kbd>:</p>
<pre><u>HERE DT RECTANGLE SIZE-STRUCTURE ALLOT .S</u> ADDRESS  OK
<u>NEW RECTANGLE CONSTANT RECT2</u>  OK</pre>
<p><kbd>SIZE-STRUCTURE</kbd> determines the size of a structure in address units. 
Just note that <kbd>SIZE-STRUCTURE</kbd> expects the data type of a structure and 
not one of its instances. Of course, structures that are not allocated in the 
dynamic memory space may not be deleted. Applying <kbd>DELETE</kbd> to a statically 
allocated structure will cause an ambiguous condition and can lead to a system 
crash.</p>
<p>Usually structures are direct children of data type <kbd>STRUCTURE</kbd>. But 
since in StrongForth structures are just stripped-down classes, it is not 
prohibited to derive a structure from a child or grandchild of <kbd>STRUCTURE</kbd>. 
What happens if you do that? Well, the new structure inherits the data members from 
its parent and allows adding additional members. The new structure is just an 
extension of the old one:</p>
<pre><u>DT RECTANGLE SIZE-STRUCTURE .</u> 16  OK
<u>DT RECTANGLE PROCREATES SCREEN-RECTANGLE</u>  OK
<u>STRUCT SCREEN-RECTANGLE</u>  OK
<u>  NULL FLAG MEMBER VISIBLE</u>  OK
<u>ENDSTRUCT</u>  OK
<u>DT SCREEN-RECTANGLE SIZE-STRUCTURE .</u> 20  OK
<u>NEW SCREEN-RECTANGLE CONSTANT SRECT</u>  OK
<u>SRECT PX .</u> 1525632  OK
<u>SRECT PY .</u> 1525636  OK
<u>SRECT WIDTH .</u> 1525640  OK
<u>SRECT HEIGHT .</u> 1525644  OK
<u>SRECT VISIBLE .</u> 1525648  OK
<u>RECT2 VISIBLE .</u>
RECT2 VISIBLE ? undefined word
RECTANGLE</pre>
<p><kbd>VISIBLE</kbd> expects an item of data type <kbd>SCREEN-RECTANGLE</kbd> 
on the stack. Since <kbd>SCREEN-RECTANGLE</kbd> is a child of <kbd>RECTANGLE</kbd>, 
<kbd>VISIBLE</kbd> cannot be applied to a <kbd>RECTANGLE</kbd>, but <kbd>PX</kbd>,
<kbd>PY</kbd>, <kbd>WIDTH</kbd> and <kbd>HEIGHT</kbd> can be applied to a 
<kbd>SCREEN-RECTANGLE</kbd>.</p>
<p>Note that a parent structure always has to be defined before its children. 
Otherwise, the definitions of a child structure couldn't determine the members 
it inherits from its parent. Of course, this restriction applies to classes as 
well. Note also that it is possible to redefine a structure (and a class). If an 
exception is thrown during a structure definition you may thus just give it a 
second try without the necessity to create a new data type for the structure.</p>
<h2>Classes</h2>
<p>The definition of a class looks quite similar to the definition of a structure. 
Classes are data types that are directly or indirectly derived from data type 
<kbd>OBJECT</kbd>, which is in turn a child of <kbd>SINGLE</kbd>. The class 
definition is enclosed between the words <kbd>CLASS</kbd> and <kbd>ENDCLASS</kbd>. 
Additionally, the word <kbd>BODY</kbd> divides the class definition in two parts 
The first part, between <kbd>CLASS</kbd> and <kbd>BODY</kbd>, will be described 
later in this chapter. Here's a first example that only uses the second 
part:</p>
<pre>DT OBJECT PROCREATES POINT

CLASS POINT
  \ first part is left empty
BODY
  \ second part starts here
  +0 MEMBER PX
  +0 MEMBER PY
  : SET-POINT ( SIGNED SIGNED POINT -- )
    LOCALS| THIS | THIS PY ! THIS PX ! ;
  : GET-POINT ( POINT -- SIGNED SIGNED )
    LOCALS| THIS | THIS PX @ THIS PY @ ;
  : POINT ( POINT -- 1ST )
    LOCALS| THIS | +0 +0 THIS SET-POINT THIS ;
ENDCLASS</pre>
<p>The class definition of <kbd>POINT</kbd> contains two data members <kbd>PX</kbd> 
and <kbd>PY</kbd> of data type <kbd>SIGNED</kbd>, plus three member words. The 
defining words for data members are the same as those you already know from 
structure definitions. Just as with structures, the data members are not 
automatically initialized. Note that <kbd>PX</kbd> and <kbd>PY</kbd> are 
overloaded versions of two of the data members of structure <kbd>RECTANGLE</kbd> 

⌨️ 快捷键说明

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