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

📄 chapter2.htm

📁 嵌入式软件开发.rar
💻 HTM
📖 第 1 页 / 共 5 页
字号:
destroyed when it is no longer needed.  When an object disappears from a program it is 
said to go out of scope.  Whenever an object goes out of scope in a C program, the 
program must execute its <a href="chapter1.htm#destructor">destructor</a>.  Otherwise, the heap--the memory area from which 
the space needed to hold additional objects--will become fully used and the program 
cannot continue without error.
<p>	The <a href="chapter1.htm#implementation_file">implementation file</a> is shown below.  The two functions increment() and 
query() are similar to the version above.  In this case these functions have pointer 
arguments, and instead of merely incrementing  or returning count, the value of count 
associated with the pointer <code>this</code> is operated on prior to the functions return.  
<pre>
 
	#include "counter1.h"
	#include  &lt;stdlib.h&gt;    /* for the memory operations */

	void increment(Counter *this)
	{
	    this->count++;
	}

	int query(Counter *this)
	{
	    return this->count;
	}

	Counter *counter_(void)
	{
	    Counter *this;
	    
	    if(this=(Counter *)(malloc(sizeof(Counter))==NULL))
		     error_handler()
	    this->count=0;
	    return this;
	}

	void counter__(Counter *this)
	{
	    free(this);
	}
</pre>
 
<p>
	The <a href="chapter1.htm#constructor">constructor</a> takes no argument and returns  pointer to a type Counter.  Inside 
the <a href="chapter1.htm#constructor">constructor</a>, a temporary pointer to a type Counter is created by the line of code
<pre>
 
	Counter *this;
</pre>
 
<p>
The system call malloc() is used to get a memory block the size of Counter.  malloc() 
returns a pointer to the type void, so the return can be cast onto a type Counter * which is 
stored in <code>this</code>.  The pointer form for member access is used to initialize count, and <code>this</code>, the 
pointer, is returned to the calling program.  The pointer returned from malloc() is tested to 
make certain that the operating system found enough memory to allocate another block to 
the program.  If there were not enough memory available, the malloc() function will return 
a NULL which cannot be a valid pointer in C.  The return value is tested to determine if it 
is a NULL.  In the event that it is, a function error_handler() is executed.  For the 
programs in this chapter, the error_handler() will be a stub routine that does nothing.  This 
important function will be revisited in Chapter 4 where an error_handler() approach will 
be developed.  The routine Counter creates a dynamic memory location which contains 
Count, initializes the value of count in that memory area, and returns a pointer to <code>this</code> 
location to the calling program. The variable <code>this</code> must always be defined in the 
<a href="chapter1.htm#constructor">constructor</a>.  In C++ there is a variable <code>this</code> that need not be defined in any <a href="chapter1.htm#method">method</a>.  This 
variable is always a pointer to the  current object.  We will use <code>this</code> as the same thing as 
you will find in C++.  Anytime that <code>this</code> is used as a variable, it will be a pointer to the 
appropriate object.
<p>   
	The <a href="chapter1.htm#destructor">destructor</a>, counter__(), uses the standard memory release call free() to return 
the  memory space occupied by the specific instance of Counter to the operating system.
<pre>
	#include "counter1.h"
	#include &lt;stdio.h&gt;

	main()
	{
	    Counter *a=counter_();
	    Counter *b=counter_();
	    int i;
	    
	    for(i=0;i&lt;12;i++)
	    {
	        increment(a);
	        increment(b);
	    }
	    for(i=0;i&lt;6;i++)
	        increment(a);
	    printf("a=%d and b=%d\n",query(a),query(b));
	    counter__(a);
	    counter__(b);	
	}
</pre>
<p>	The performance of this version of Counter is demonstrated by the above program.  
Two instances of a counter are created by the two lines of code   
<pre>
 
	Counter *a=counter_();
	Counter *b=counter_();
</pre>
 
<p>
Each line of code says:
<p><i>
  	Create an instance of a pointer to the type Counter.  Initialize the pointer with the 
	return from the <a href="chapter1.htm#constructor">constructor</a> function counter_().  These lines of code are 
	definition statements as well as initialization statements.
</i><p>
For demonstration purposes, the program increments both a and b twelve times and then 
increments a an additional six times.  The output from this program is
<pre>
 
	a=18 and b=12
</pre>
 
<p>
We have succeeded in modifying our approach to the creation of objects in C to allow 
multiple instances of a single object. Notice that the <a href="chapter1.htm#destructor">destructor</a> was used at the end of the 
program to delete the instances of a and b that were created with the <a href="chapter1.htm#constructor">constructor</a>.
<p>	The approach outlined above handily eliminates the problem of multiple 
instantiations.  The program can now have as many instances of any given class as is 
needed to meet the program needs.  The cost so far to achieve these ends is minimal.  
There is one copy of each <a href="chapter1.htm#method">method</a>, the <a href="chapter1.htm#constructor">constructor</a> and the <a href="chapter1.htm#destructor">destructor</a> associated with each 
program.  In this case, each object will be two bytes long, and the <a href="chapter1.htm#constructor">constructor</a> will allocate 
exactly two bytes for each instance of the object.  The object oriented approach has cost 
nothing with the exception of the additional function calls in the main program needed to 
set-up the objects and access the object <a href="chapter1.htm#attribute">attribute</a>s.  We have gained the ability to deal with 
Counters as an object.  The <a href="chapter1.htm#method">method</a> function calls above are really mechanisms to send and 
receive messages to and from the object.  Such accesses are uniform across the whole 
program, and the code created to access the Counters is very simple and to the point.  
This particular program is so simple that many would say that it is easier to write the code 
to do the job in other ways.  Perhaps true, but in no case would the straight procedural 
approach be so obvious as to what the program is doing. 
<p>	If our program approach is to allow multiple instances of any object, it is necessary 
to have arguments for all object <a href="chapter1.htm#method">method</a>s.  The problem here is that the program has no 
means of determining which object is sending a message to any specific <a href="chapter1.htm#method">method</a>.  
Therefore, the object identification must be included  as a part of the message that is 
passed to the <a href="chapter1.htm#method">method</a>.  We will see later that when more complicated functions like virtual 
functions  and <a href="chapter1.htm#inheritance">inheritance</a> are employed, even a single additional argument  is not 
sufficient to identify accurately the program destination when a message is sent to an 
object.

<h2><a name="inheritance"><a href="chapter1.htm#inheritance">Inheritance</a></a></h2>
 
	The current approach outlined above does not allow either <a href="chapter1.htm#inheritance">inheritance</a> or 
<a href="chapter1.htm#polymorphism">polymorphism</a> as it stands.  These features are so important that they must be considered 
when creating an object oriented method of programming.  Inheritance allows a new class 
to access all of the <a href="chapter1.htm#attribute">attribute</a>s and <a href="chapter1.htm#method">method</a>s of another class as if they were its own.  The 
new class can extend the capability of the class being inherited from.  Semantic problems 
creep into our list of difficulties with OOP now.  Inheritance is a poor description of what 
we are doing at this point.  Inheritance usually implies the passage of characteristics and 
traits from parent to child.  Often the classes are given the name parent and child class.  As 
it turns out, this naming is not truly descriptive of what happens in OOP <a href="chapter1.htm#inheritance">inheritance</a>.  The 
parent class gives all of its <a href="chapter1.htm#attribute">attribute</a>s and <a href="chapter1.htm#method">method</a>s to the child class.  The parent class can 
operate on its own, but the child class is forever dependent on the presence of the parent.  
An unlikely <a href="chapter1.htm#parent">parent</a>-
<a href="chapter1.htm#child">child</a>
 arrangement if ever there was one.  Sometimes the parent class is 
called the base class or the super class.  In such cases, the child class is usually called the 
derived class.  These descriptions probably convey the actual happenings in <a href="chapter1.htm#inheritance">inheritance</a> 
better than the parent-child concept.  We will continue to use <a href="chapter1.htm#inheritance">inheritance</a> here to describe 
what occurs when a new class takes all of the characteristics of another class, but 
recognize that such an action is not <a href="chapter1.htm#inheritance">inheritance</a> in any real sense.  
<p>	Let us examine what we can do to implement OOP <a href="chapter1.htm#inheritance">inheritance</a> in the C language 
without the OOP extensions found in C++.  To create <a href="chapter1.htm#inheritance">inheritance</a>, we really need a 
mechanism to alter the structure that defines a class in another part of the program.  True 
<a href="chapter1.htm#inheritance">inheritance</a> will allow the characteristics of the base structure to be incorporated into a 
new structure in the process of derivation of the new structure.  
<p>	Once a structure has been defined by a program, it is not possible to change it.  
When inheriting, it is possible to include another class structure as a member of a new 
class structure.  Such an approach will lead to extremely convoluted programs, and one of 
the purposes of OOP is to create uniform, smooth interfaces between portions of a 
program.  The idea of using one class structure as a member of another class structure will 
lead to at least multiple indirection on accesses to the object <a href="chapter1.htm#attribute">attribute</a>s and <a href="chapter1.htm#method">method</a>s.  
Some accesses would require one level of indirection, and others would require more.  
What a nightmare! 
<p>	An approach shall be developed that does require some indirection, but the 
indirection levels needed by the programmer will be uniform.  Therefore, the demands on 
the programmer are somewhat more complicated than usual, but the benefits gained by 
having the OOP significantly outweigh the need for additional programmer involvement.
In the following <a href="chapter1.htm#header">header file</a>, observe that the #define statement that defines COUNT 
contains items that are the <a href="chapter1.htm#attribute">attribute</a>s as well as function prototypes for the class typedefed 
as Count.  The <a href="chapter1.htm#method">method</a> prototypes use pointers to functions rather than the normal 
function name, and the arguments to these functions are pointers to the type struct cnt.  It 
is not possible to use a pointer to the type Count, because Count is an undefined type at 
this point in the program.  The class declaration is the structure cnt, and this structure is  
typedefed as a type Count when it is created.  The members of struct cnt are simply those 
items defined as COUNT.  As was done earlier, the <a href="chapter1.htm#constructor">constructor</a> and <a href="chapter1.htm#destructor">destructor</a> are 
prototyped in the <a href="chapter1.htm#header">header file</a> named counter2.h.  
<pre>
 
	#ifndef COUNT_H
	#define COUNT_H

	#include "defines.h"

	#define COUNT  \
	    WORD count;  \
	    void (*increment)(struct cnt *);\
	    WORD (*query)(struct cnt *);


	typedef struct cnt
	{
	    COUNT
	}Count;                                                        

	Count *count_(void);
	void count__(Count *);

	#endif
</pre>
 
<p>
	The main difference between this header and the previous one is that the member 
<a href="chapter1.htm#attribute">attribute</a>s and <a href="chapter1.htm#method">method</a>s that are a part of the class are each defined in the #define 
statement.  The reason for this approach is not evident right now, but we will see the 
importance of making these several members of the structure a seaprately accessable entity 
and not keeping their definitions locked inside of the structure which defines the class.
<p>	The <a href="chapter1.htm#implementation_file">implementation file</a> is shown below.  One of the first items that you will 
observe is that the <a href="chapter1.htm#method">method</a> function implementations are declared to be static.  A static 
declaration for a function causes the function to have file scope.  Therefore, if another 
portion of the program needs an increment, there will be no name conflicts if the various 
files are each compiled separately.  Otherwise, the functions increment() and query() are 
the same as those shown in the earlier counter1 version of the class.
<pre>

	#include "counter2.h"
	#include &lt;stdlib.h&gt;    /* needed for the memory functions */

	static void increment(Count *this)
	{
	    this->count++;
	}

	static WORD query(Count *this)
	{
	    return this->count;
	}

	Count *count_(void)
	{
	    Count *this;
	    
	    if((this=(Count *)malloc(sizeof(Count)))==NULL)
		  error_handler();
	    this->count=0;
	    this->increment=increment;
	    this->query=query;
	    return this;
	}

	void count__(Count *this)
	{
	    free(this);
	}
</pre>

<p>	The <a href="chapter1.htm#constructor">constructor</a> count_() is significantly modified from the earlier version.  Here, 
the memory space for the object is allocated, and the <a href="chapter1.htm#attribute">attribute</a> count is initialized to zero.  
In this case, the two <a href="chapter1.htm#method">method</a> members of the structure are initialized with pointers to the 
functions increment() and query() defined earlier in the <a href="chapter1.htm#implementation_file">implementation file</a>.  Therefore, 
any access to these functions must take the form
<pre>
 
	Count *a=count_();
	.
	.
	.
	(*a->increment)(a);
	.
	.
</pre>
 

⌨️ 快捷键说明

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