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

📄 oopc.html

📁 c语言是面向过程的程序语言
💻 HTML
📖 第 1 页 / 共 5 页
字号:
(C++: member function).</li><li>A hidden member constant pointer <tt>__vptr</tt> to its <i>virtual table</i>.</li></ul>OOPC macros achieve simply the class definition (and declaration) whichin reality looks nearly like:<blockquote><tt>struct _ooc_class_person {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* generated */</tt><br><tt>&nbsp; struct _ooc_vtbl_person const*const <b>__vptr</b>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* generated */</tt><br><tt>&nbsp; t_person (*const person)(void);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* generated */</tt><br><tt>&nbsp; void (*const _person)(t_person *const <b>this</b>);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* defined&nbsp;&nbsp; */</tt><br><tt>&nbsp; t_person *const (*const alloc)(void);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* generated */</tt><p><tt>&nbsp; t_person *const (*const new)(char const name[]);</tt><br><tt>&nbsp; void (*const init)(t_person *const <b>this</b>, char constname[]);</tt><p><tt>} person;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* generated */</tt></blockquote>by the equivalent (which must follow the object interface, see <tt><a href="examples/person.h">person.h</a></tt>for a complete interface):<blockquote><b><tt>CLASS_INTERFACE</tt></b><p><tt>&nbsp; t_person *const <b>classMethod_</b>(new) char const name[]__;</tt><br><tt>&nbsp; void <b>method_</b>(init) char const name[] __;</tt><p><b><tt>ENDOF_INTERFACE</tt></b></blockquote>Here, the declared variable <tt>person</tt> is the class <i>itself</i>of person while <tt>t_person</tt> has been previously defined to be theobject <i>type</i> of person. The important difference appearing here isthat we need only one class person (instance) while we need a lot of objectsperson (instances). The hidden type <tt>struct _ooc_class_person</tt> shouldnever be used (no necessity).<p>In the class definition and declaration above, we make the differencebetween the <i>class method</i> and the <i>method</i>. The latter requiresa <tt>t_<i>object</i> *const</tt> (i.e. <tt>t_person *const</tt>) as itfirst argument and this pointer is referenced as the <tt>this</tt> pointerinside the method (C++: <tt>this</tt>). If the method is a constant method(C++: constant member function), the <tt>this</tt> pointer will be of type<tt>t_<i>object</i>const*const</tt>. Class methods returning a <tt>t_<i>object</i>*</tt> arecalled <i>objects factory</i>.<p>The special<tt>_(<i>args</i>) <i>args</i> __</tt> declaration is themechanism used to extend the <tt>method</tt> macro to any number of arguments.Each time a <b>token/keyword finishes with a <tt>_ </tt>it waits for theclosure<tt>__</tt></b>. This artifact is not required if you have a C99preprocessor (see <a href="#ISO_C99">ISO C99</a>).<p>Note: If you don't know where to put your methods, you should remindthat classes should only contain <i>class methods</i> like <tt>new()</tt>(object factory) and methods strongly related to the object type like <tt>init()</tt>and <tt>copy()</tt>. All other methods should be considered as object methods.If you have any doubts, use object methods, this will avoid any big changesin future interfaces of derived classes. Moving a method from the objectdefinition to the class definition bring only slights changes (remove polymorphism).Moving a method from the class definition to the object definition canbe a major task of a project (add polymorphism).<br>&nbsp;<table CELLPADDING=5 COLS=1 WIDTH="100%" BGCOLOR="#66FFFF" NOSAVE ><tr NOSAVE><td NOSAVE><a NAME="Messages"></a><b><font face="Arial,Helvetica"><font size=+2>Messages</font></font></b></td></tr></table><p>In order to use <tt>person</tt> objects in our program, we still needto know how to <i>send messages</i> to an object. In this section we usethe terminology <i>sending messages (to an object)</i> while in the <a href="#Methods">Methods</a>section, we use the terminology<i>calling methods (of a class)</i>. Wealways send a message to an object by using the two commands<tt>sendMsg(<i>object</i>,<i>message</i>)</tt>and<tt>sendMsg_(<i>object</i>,<i>message</i>)<i>args</i> __</tt>:<blockquote><tt>t_person *const per = person.new("Brown");</tt><br><tt><b>sendMsg</b>(per, print);</tt><br><tt><b>delete</b>(per);</tt></blockquote>The first line creates (allocates and initializes) a new person <tt>per</tt>with some initialization arguments (<tt>"Brown"</tt>). As we have seenin the class definition,<tt>new</tt> is a <i>class method</i> and canonly be called throughout its class. If object dynamic allocation fails,the exception <tt>ooc_bad_alloc</tt> is thrown (see <a href="#Exceptions">Exceptions</a>).The following line print the <tt>per</tt> object by <i>sending</i> the<tt>print</tt><i>message</i>to the object<tt>per</tt>. The command <tt>delete()</tt> is a specialmacro which always delete properly an object by calling its destructorand then freeing the object instance. If you need a function pointer to<tt>delete()</tt>(see<a href="#Exceptions">Exceptions</a>), use <tt>ooc_delete()</tt> instead.Obviously, messages can only be sent to properly initialized objects. Itis also possible to work with automatic objects to avoid dynamic allocation:<blockquote><tt>t_person per[1] = { person.person() };</tt><br><tt>person.init(per, "Brown");</tt><br><tt><b>sendMsg</b>(per, print);</tt><br><tt>person._person(per);</tt></blockquote>The first line initialize a new person <tt>per</tt> using the <i>objectconstructor</i> <tt>person()</tt> automatically provided for each class(see<a href="#Interface">Interface</a>). Like for the <tt>new</tt> classmethod, the constructor must be called throughout its class. After thisstep, <tt>per</tt> is a well formed object, but not yet initialized andthis is done by the second line where the method<tt>init</tt> is calledto initialize the object. The following line print the <tt>per</tt> objectby <i>sending</i> the appropriate<i>message</i> to the object <tt>per</tt>.Finally the object <tt>per</tt> is cleared but not deleted since it isnot a dynamically allocated object (automatic object). Basically, eachtime you use an equivalent of <tt>new</tt> (resp. <tt>init</tt>) to create/initializean object, you probably must use <tt>delete</tt> (resp.<tt>_<i>object</i></tt>)to destroy this object before the end of its scope. <tt>init()</tt> isa method and not a message since it is strongly related to the object typeand therefore will never be polymorphic.<p>In the example above, we have declared <tt>per</tt> as an array to avoidthe <tt>&amp;</tt> in the macros. If your compiler complains about thefirst line you can either do the initialization after the declaration oruse the following alternative:<blockquote><tt>t_person per = person.person();</tt><br><tt>person.init(&amp;per, "Brown");</tt><br><tt><b>sendMsg</b>(&amp;per, print);</tt><br><tt>person._person(&amp;per);</tt></blockquote>Dealing with array of automatic objects may be a little more complex:<blockquote><tt>int i;</tt><br><tt>t_person per_ref = person.person();</tt><br><tt>t_person per[100];</tt><p><tt>for(i=0; i&lt;100; i++) {</tt><br><tt>&nbsp; memcpy(per +i, &amp;per_ref, sizeof(t_person));</tt><br><tt>&nbsp; person.init(per +i, "Unkown");</tt><br><tt>}</tt><p><tt>for(i=0; i&lt;100; i++) {</tt><br><tt><b>&nbsp; sendMsg</b>(per +i, print);</tt><br><tt>}</tt><p><tt>for(i=0; i&lt;100; i++) {</tt><br><tt>&nbsp; person._person(per +i);</tt><br><tt>}</tt></blockquote>The use of <tt>memcpy()</tt> is required to cast away the constant specifierof <tt>__vptr</tt> to avoid any objects bitwise copy. To allow such objectscopy (this assumes that you know what you do), you can compile your C fileswith the flag <tt>-DALLOW_OBJCOPY</tt>. Then the statement <tt>per[i] =per_ref;</tt> will become valid. The macro <tt>objCopy(obj1, obj2)</tt>will be substituted by the assignment statement (i.e. <tt>obj1=obj2</tt>)if<tt>-DALLOW_OBJCOPY</tt> is specified or else by <tt>memcpy</tt>.(i.e.<tt>memcpy(&amp;obj1,&amp;obj2, sizeof(obj1))</tt>). Obviously, this macro waits for objectsinstance, not objects addresses, to be able to compute objects size. Ifautomatic object array manipulation is important, it would be better towrite the <tt>initArr(size, args)</tt> and <tt>clearArr(size)</tt> methodsfor this purpose.<br>&nbsp;<table CELLPADDING=5 COLS=1 WIDTH="100%" BGCOLOR="#66FFFF" NOSAVE ><tr NOSAVE><td NOSAVE><a NAME="Methods"></a><b><font face="Arial,Helvetica"><font size=+2>Methods</font></font></b></td></tr></table><p>If you know the <b><u>exact</u></b> class of an object, <i>sending</i>a message can be replaced by the <i>call</i> of the object's method throughoutits class like for the methods and class methods. For example,<blockquote><tt><b>sendMsg</b>(per, print);</tt></blockquote>is equivalent to<blockquote><tt><b>sendCMsg</b>(per, person, print);</tt></blockquote>But beware that you can <b>involuntary call the wrong object method</b>if for example it has been overloaded (see <a href="#Polymorphism">Polymorphism</a>).That is why it is mainly reserved for the class implementation where usuallyobjects types are well known and where using object methods through theirclass is the only way to bypass the polymorphism mechanism. Another safesolution is:<blockquote><tt><b>methodAddr</b>(per, print)(per);</tt></blockquote>where <tt>methodAddr()</tt> returns a constant pointer to the object'smethod, but <tt>per</tt> appears twice in the statement and it is not veryelegant comparing to the use of <tt>sendMsg()</tt>. To be complete, theequivalent of the <tt>sendCMsg()</tt> used above would be:<blockquote><tt><b>methodAddr</b>(&amp;person, print)(per);</tt></blockquote>Note: messages and methods are function pointers and therefore can be usedas such.<br>&nbsp;<table CELLPADDING=5 COLS=1 WIDTH="100%" BGCOLOR="#66FFFF" NOSAVE ><tr NOSAVE><td NOSAVE><a NAME="Encapsulation"></a><b><font face="Arial,Helvetica"><font size=+2>Encapsulation</font></font></b></td></tr></table><p>Leaving objects members to public access can bring serious data integrityproblem like changing the stored size of an array without adjusting thearray size. One way to protect data and methods is to declare them as <tt>private</tt>.Private members can only be accessed by their class or subclasses (see<a href="#Inheritance">Inheritance</a>).So it is wise to declare <tt>private</tt> all members that should not beaccessible by objects users.<p>Private specification can be applied to the object data and methodsas well as to class data and methods. Sometimes, for simplicity or efficiency,it is also useful to have direct access to object members like for thecomplex number object:<blockquote><tt>#define <b>OBJECT</b> complex</tt><p><b><tt>BASEOBJECT_INTERFACE</tt></b><p><tt>&nbsp; double <b>public</b>(real);</tt><br><tt>&nbsp; double <b>public</b>(imag);</tt><p><b><tt>BASEOBJECT_METHODS</tt></b><p><tt>&nbsp; /* no virtual function */</tt><p><b><tt>ENDOF_INTERFACE</tt></b></blockquote><i>Public</i> and <i>private</i> members and methods can be intermixedwithout any problem. To reach a public member of an object, you do exactlyas for structures:<blockquote><tt>t_complex *const j = complex.alloc();</tt><br><tt>j->m.imag = -1;</tt></blockquote><table CELLPADDING=5 COLS=1 WIDTH="100%" BGCOLOR="#66FFFF" NOSAVE ><tr NOSAVE><td NOSAVE><a NAME="Interface"></a><b><font face="Arial,Helvetica"><font size=+2>Interface</font></font></b></td></tr></table><p>The interface is simply where object and class definition take place,usually in a header file (<tt><a href="examples/person.h">person.h</a></tt>)which looks like:<blockquote><tt>#ifndef PERSON_H</tt><br><tt>#define PERSON_H</tt><p><tt>#include &lt;ooc.h></tt><p><tt>#undef&nbsp; OBJECT</tt><br><tt>#define <b>OBJECT</b> person</tt><p><b><tt>BASEOBJECT_INTERFACE</tt></b><p><tt>&nbsp; char const* <b>private</b>(name);</tt><p><b><tt>BASEOBJECT_METHODS</tt></b><p><tt>&nbsp; void <b>constMethod</b>(print);</tt><p><b><tt>ENDOF_INTERFACE</tt></b><p><b><tt>CLASS_INTERFACE</tt></b><p><tt>&nbsp; t_person *const <b>classMethod_</b>(new) char const name[]<b>__</b>;</tt><br><tt>&nbsp; void <b>method_</b>(init) char const name[] <b>__</b>;</tt><br><tt>&nbsp; void <b>method_</b>(copy) t_person const*const per __;</tt><p><b><tt>ENDOF_INTERFACE</tt></b><p><tt>#endif</tt></blockquote>This file is split into two parts which describe the object and class definitionas seen before. One new thing to note is the inclusion of the header file<tt>ooc.h</tt>whichprovides a set of useful keywords and macros like (<tt>BASE</tt>)<tt>OBJECT_INTERFACE</tt>,(<tt>BASE</tt>)<tt>OBJECT_METHODS</tt>, (<tt>ABSTRACT</tt>)<tt>CLASS_INTERFACE</tt>and<tt>ENDOF_INTERFACE</tt> (see <a href="#Keywords">Keywords</a>). Macros<tt>XXX_INTERFACE</tt>delimit sections of the object and class interface definition. Anotherthing is the declaration of<tt>OBJECT</tt> as <tt>person</tt> which specifiesthe class name for the interface and the implementation and creates automaticallythe declaration <tt>t_OBJECT</tt> which is the generic name of the objecttype (i.e. <tt>t_person</tt>, see <a href="#Genericity">Genericity</a>).We also find the <tt>print</tt> method which prints a person's name. Since

⌨️ 快捷键说明

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