📄 chapter2.htm
字号:
<a href="chapter1.htm#method">method</a> will operate upon. (This approach may seem strange for object oriented
programming. If you examine the C code generated by a cfront, you will find that this is
exactly the way that the different instantiations of the same object are kept separated. )
<pre>
#include "graph.h"
static Boolean is_visible(Graph* this) /* is visible */
{
return this->visible;
}
static void hide(Graph* this) /* hide */
{
}
static void show(Graph* this) /* show */
{
}
/* move to a new location */
static void move( Graph* this, int new_x, int new_y)
{
(*this->hide)(this);
this->x=new_x;
this->y=new_y;
move_to(new_x,new_y);
(*this->show)(this);
}
</pre>
<p> The above <a href="chapter1.htm#method">method</a>s are straight-forward and simple as you would expect with any
object oriented programming <a href="chapter1.htm#method">method</a>s. All of the <a href="chapter1.htm#method">method</a>s are static limiting visibility to
the file in which they are defined. Therefore, if another class would use <a href="chapter1.htm#method">method</a>s with the
same name, there would be no name resolution problems. The first <a href="chapter1.htm#method">method</a> is_visible()
returns the state visible for the specified object. hide() and show() are stub functions that
have no code for the abstract function. These functions are the virtual functions of the
abstract class and they will be completed in any class that uses Graph as a superclass.
The <a href="chapter1.htm#method">method</a> move() first hides the pixel, establishes a new position, and then shows the
new point.
<p> The code for the <a href="chapter1.htm#constructor">constructor</a> of Graph is shown below. This <a href="chapter1.htm#constructor">constructor</a> will
return a pointer to the type Graph that will be associated with the particular instantiation
of the object through the whole program. In the <a href="chapter1.htm#constructor">constructor</a>, the variable <code>this</code> is a pointer
to a type Graph. There is no memory allocated where the object can be stored. Since we
cannot know how many objects of different types will be created, dynamic allocation is
used to create memory for these variables. The malloc() function call will provide a
pointer of the type void to a memory space the size of Graph. The pointer is cast onto a
pointer to a type Graph and then assigned to <code>this</code>.
<pre>
/* graph constructor */
Graph* graph_(int x, int y, int background,
int foreground)
{
Graph* this;
if((this=(Graph *)malloc(sizeof(Graph)))==NULL)
error_handler();
this->is_visible=is_visible;
this->show=show;
this->hide=hide;
this->move=move;
this->x=x;
this->y=y;
this->background=background;
this->foreground=foreground;
this->visible=FALSE;
return this;
}
</pre>
<p> The next four statements in the above code place the addresses of the class
<a href="chapter1.htm#method">method</a>s into the proper locations in the newly defined object. The following four
statements place the argument values into the proper location in the object, and finally, the
new object is marked as invisible. The pointer to this specific object is then returned to
the calling program.
<p> The object <a href="chapter1.htm#destructor">destructor</a> is shown below. This function has as a parameter a pointer
to the type Graph. The memory space for this particular object is freed by the <a href="chapter1.htm#destructor">destructor</a>
after its image is removed from the screen.
<pre>
/* graphics point destructor */
void graph__(Graph* this)
{
hide(this); /* hide before destroying */
free(this);
}
</pre>
<p> The above class definition cannot be used for a demonstration. The essential
functions hide() and show() are merely stubs. These functions are essential to the
operation of the class. Let us examine <a href="chapter1.htm#inheritance">inheritance</a> first and then demonstrate both the use
of a Graph as well as it child.
<p> Many graphics objects can be inherited from Graph. Several potential graphics
objects might include a circle, a point, and a rectangle. The common link that connects
the items is that they are all Graph items. It is entirely possible that we could have an
object that has many of the <a href="chapter1.htm#attribute">attribute</a>s of Graph but it is still is not a Graph item. For
example, consider a golf ball. A golf ball could have a location, an x and a y; it could have
a foreground color against a background color; and the <a href="chapter1.htm#method">method</a>s hide, show and move are
excellent choices of functions to operate on a golf ball. Also, is_visible() is a perfect
<a href="chapter1.htm#method">method</a> for the operation of a golf ball that might be hiding in the rough. So a golf ball
would have <a href="chapter1.htm#attribute">attribute</a>s and classes exactly the same as a Graph item. However, a golf ball
is not a Graph item, so a golf ball should not be created as a descendent of a Graph.
<p> If we should look at the definition files for some pratical descendent classes--Point,
Circle and Rectangle-- we would see that they share common <a href="chapter1.htm#method">method</a>s and <a href="chapter1.htm#attribute">attribute</a>s as
well as being a Graph object. Some if the characteristics of these classes are best seen in a
figure as is shown below.
<p><img align=middle src="fig2-1.jpg">
<p>
<p>
<h4>Figure 2.1 Common Members found in Point, Circle and Rectangle </h4>
<p> Observe in this figure that the first nine members of each class are the same, and in
fact these nine members are identical to the corresponding members of the class Graph.
These classes are extensions of the class Graph, and the three classes Point, Circle, and
Rectangle are each merely slight variations of the base class Graph. They each meet the
"is a" requirement that allows them to inherit the characteristics of Graph. As such, the
nine common members including the nonvirtual <a href="chapter1.htm#method">method</a>s is_visible() and move() from the
base class can be used by the derived classes. The virtual classes are each unique to the
derived classes and must be written specifically for each derived class. The rewritten
classes to include the <a href="chapter1.htm#inheritance">inheritance</a> are as shown in Figure 2.
<p>
<p><img align=middle src="fig2-2.jpg">
<p>
<h4>Figure 2.2 Creating an Heirarchy by Inheritance</h4>
<p> The base class Graph is shown above the three derived classes, and the derived
classes are shown in boxes below. Each of these classes has the needed parts of any class.
Note that the point class has no unique members that differ from the base class. The circle
class has some unique members because it needs both a radius and the grow() functions
that are not a part of the base class. Here a new <a href="chapter1.htm#method">method</a> grow and a new <a href="chapter1.htm#attribute">attribute</a> radius
complete a circle. The rectangle class needs a new <a href="chapter1.htm#method">method</a> called resize and two new
<a href="chapter1.htm#attribute">attribute</a>s needed to define uniquely the location of a rectangle on the screen.
<p> The members of GRAPH_CLASS are used as the basis for creation of each new
class. GRAPH_CLASS is extended in each case to include new members essential to the
new class. Also, each <a href="chapter1.htm#constructor">constructor</a> prototype is altered to have an approprate number of
arguments. Let us look at the <a href="chapter1.htm#implementation_file">implementation file</a>s for these classes.
<p> Observe that the elements of Point are already found in Graph. Therefore, the
implementation must supply only the functions that are the virtual functions not provided
in the implementation of Graph. Of course, each <a href="chapter1.htm#implementation_file">implementation file</a> must contain both a
<a href="chapter1.htm#constructor">constructor</a> and a <a href="chapter1.htm#destructor">destructor</a>. The code for the Point <a href="chapter1.htm#implementation_file">implementation file</a> is as follows:
<pre>
#include "point.h"
static void hide(Point* this) /* hide */
{
this->visible=FALSE;
pen_color(this->background);
setpixel(this->x,this->y);
}
static void show(Point* this) /* show */
{
this->visible=TRUE;
pen_color(this->foreground);
setpixel(this->x,this->y);
}
/* point constructor */
Point* point_(int x, int y, int background,
int foreground)
{
Graph* temp=graph_(x,y,background,foreground);
Point* this;
if((this=(Point *)malloc(sizeof(Point)))==NULL)
error_handler();
memmove(this,temp,sizeof(Graph));
graph__(temp);
this->show=show;
this->hide=hide;
return this;
}
/* graphics point destructor */
void point__(Point* this)
{
hide(this); /* remove from screen before destroying */
free(this);
}
</pre>
<p>The implementation of circle is typical for an inherited class. If a <a href="chapter1.htm#method">method</a> is unique
to the inherited class, it must be redone in the implementation. If it is not different from
the code in the base class, the code in the base class can be used without change in the
descendent class. For example, the only <a href="chapter1.htm#method">method</a>s that need to be changed in Circle are the
<a href="chapter1.htm#method">method</a>s hide() and show(). These <a href="chapter1.htm#method">method</a>s must draw circles on the screen while the
same <a href="chapter1.htm#method">method</a>s in Graph merely drew a pixel on the screen. Therefore, these two <a href="chapter1.htm#method">method</a>s
must be rewritten for Circle. The <a href="chapter1.htm#method">method</a> move() is unchanged when linked into either
Graph or Circle. Therefore, it needs not be repeated in Circle. The new <a href="chapter1.htm#method">method</a> grow() is
also included.
<pre>
#include "circle.h"
static void hide(Circle* this)
{
this->visible=FALSE;
move_to(this->x,this->y);
circle(this->radius,this->background);
}
static void show(Circle* this)
{
this->visible=TRUE;
move_to(this->x,this->y);
circle(this->radius,this->foreground);
}
static void grow(Circle* this, int del_radius)
{
(*this->hide)(this);
this->radius+=del_radius;
(*this->show)(this);
}
</pre>
<p>The <a href="chapter1.htm#constructor">constructor</a> circle_() shows the typical approach to use of <a href="chapter1.htm#inheritance">inheritance</a>. Here, two
objects are needed, one of the type Graph* and the other of the type Circle*. An instance
of the type Graph is created using the <a href="chapter1.htm#constructor">constructor</a> graph_(). This instance will have the x
and y location of the center of the circle, and on a screen with a background and
foreground specified for the circle. Then the memory for the type Circle is allocated, and
the data contained in the instantiation of Graph is copied onto this memory location. At
that point there is no longer a need for temp, so it is destroyed by a graph__(temp) call.
<pre>
Circle* circle_(int x, int y, int radius,
int background, int foreground)
{
Graph* temp;
Circle* this;
temp=graph_(x,y,background,foreground);
if((this=(Circle*) malloc(sizeof(Circle)))==NULL)
error_handler();
memmove(this,temp,sizeof(Graph));
graph__(temp);
this->hide=hide;
this->show=show;
this->grow=grow;
this->radius=radius;
return this;
}
void circle__(Circle* this)
{
hide(this); /* hide before destroying */
free(this);
}
</pre>
<p>The new <a href="chapter1.htm#method">method</a>s are now placed into the new instance of the object. A pointer to
this new object is returned to the calling program. The class Circle here has inherited all
of the members of the class Graph. In those instances where the <a href="chapter1.htm#method">method</a>s of Graph are
not usable in Circle, new <a href="chapter1.htm#method">method</a>s are inserted. Methods and <a href="chapter1.htm#attribute">attribute</a>s unique to Circle
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -