Appendix B Creating Wrapped Classes
========================== // Uninterpreted C++ code belongs in here. /* The bar above and below it must be on lines by themselves. */ ==========================Outside of these uninterpreted blocks use single line (//) comments to annotate the wrap file, anywhere but the delimiter (====) lines.
notice ====================================================================== /* * * $Header: /mit/ceci/1/aybee/devl/doc/firstRel/RCS/DSintStackRO.wrp, v 1.1 1995/06/02 21:23:23 aybee Exp aybee $ * * Copyright 1993, 1994, 1995 Massachusetts Institute of Technology. * All rights reserved. * AthenaMuse is a registered trademark of the Massachusetts * Institute of Technology. */ ====================================================================== foundation: IntStack wrapped: DSintStack module: ExampleModule abstract: false header ====================================================================== #include <IntStack.h> /* * IntStack.h hypothetically includes something like... * * class IntStack * { * public: * int getHeight(); * void push(int); * int pop (); * int isEmpty(); * }; * */ ====================================================================== source ====================================================================== #include <control/EXmodule.h> #include <control/DSintStackRO.h> #include <adl/ERsemantic.h> ====================================================================== superclasses { } codeFragments { constructor ====================================================================== mpWrapped = new IntStack; ====================================================================== } members { private: published: name { get: default set: default } height { get: custom set: none } } methods { private: void localDestroy() ====================================================================== if (mpWrapped) delete mpWrapped; ====================================================================== UTvalue _Get_height() const ====================================================================== return mpWrapped->getHeight(); ====================================================================== published: void Push( integer_t newTop ) ====================================================================== /* effects: puts newTop on the top of the stack */ mpWrapped->push( newTop ); ====================================================================== integer_t Pop() ====================================================================== /* returns: removes top value from the stack and returns it */ assert( ! mpWrapped->isEmpty() ); return mpWrapped->pop(); ====================================================================== }
This is a required field and you must use one of these declarations to tell the wrap script the type of the foundation class:
foundation: classNameThis line must contain the designation foundation: followed by the name of foundation class. The mpWrapped member is of type className. In the few cases where there is no underlying foundation class to support the wrapped class, you can specify void as the class name.
foundationRO: classNameROThis line must contain the designation foundationRO: followed by the name of foundation class that includes the RO suffix. The mpWrapped member is of type classNameRO.
For your convenience the wrap script provides two macros WRAP_FOUNDATION and WRAP_FOUNDATION_PTR, defined as the name of the foundation class and the type of a pointer to that class respectively. These become especially useful when you want to take advantage of wrapper inheritance, as discussed in Section B.2, "Inheritance Model of the Wrap Script" page 280.
wrapped: nameOfWrappedClassInADLThis is a required field and must contain the designation wrapped: followed by the name of the wrapped class in the ADL. The latter must be a legal ADL identifier. (See Section 3.2, "Identifiers" page 14.)
module: moduleNameThis is a required field and must contain the module name followed by a legal ADL identifier. See Section B.2, "Inheritance Model of the Wrap Script" page 280 for an explanation about the module mechanism that AM2 uses. You must add a line such as UT_FORCE_LOAD(nameOfWrappedClassInADL) to the appropriate module source file to force the linker to pull in the newly wrapped class.
This is a required field. The boolean must be either TRUE or FALSE. If true, this class may not be instantiated in the ADL. This becomes useful when you use wrapped class inheritance and have base classes that should not be instantiated.
This is an optional field. The boolean must be either true or false. If true, ADL programmers may use this class as a direct base of any ADL class. Usually, only abstract classes may not have a subclass in the ADL. As a result, the default value for this characteristic is the logical not of the previous declaration abstract. If a class is abstract, then the default is that you cannot create a subclass in the ADL; if a class is not abstract, then the default is that you can create a subclass in the ADL.
wrappedClassNameRO(const MCprogramObjectRP& pParent, const MCinstanceRP& pDerived= gkpNullInstPtr) mpWrapped( 0 ) { // ...contents of "preConstructor" fragment here... // ...contents of "constructor" fragment here... }
wrappedClassNameRO(WRAP_FOUNDATION_PTR pWrapped, const MCprogramObjectRP& pParent, const MCinstanceRP& pDerived=gkpNullInstPtr) { mpWrapped = pWrapped; // ...contents of preConstructor fragment here... // ...contents of constructorFromFoundation fragment here... }
void wrappedIsReady() { /* fragment code here */ }
A wrapped object should call the wrappedIsReady() function when the foundation object it wraps is ready. This is very useful in the case of wrapper inheritance, further discussed in Section B.2, "Inheritance Model of the Wrap Script" page 280.
void preDestroy() { /* fragment code here */ } void postDestroy() { /* fragment code here */ }
The wrapped object's Destroy method then has the following body:[20]
{ preDestroy(); //only inserted if preDestroy exists localDestroy(); //only inserted if localDestroy exists mpWrapped = NULL; postDestroy(); //only inserted if postDestroy exists MCcxxObjectRO::Destroy();//normal upchained Destroy call }
The members of a wrapped class have four protection levels: private, protected, and public in C++, and published in the wrapper. The wrap script prepares members in the published category, making them available to the ADL run-time engine. You can separate member descriptions into protection levels by placing the protection level name followed by a colon, such as
private:
on a separate line. All subsequent lines until the next protection level designation or the final delimiter ( } ) are given that protection level. The wrap script does not interpret lines with a C++ protection level of private, protected, or public. They go directly into a similarly protected section of the generated header.
Published members appear to the ADL as instance members of the published class. There are two generic operations performed on simple members: get and set. Use the get operation when an ADL program needs the value of a member, and the set operation when the program assigns a value to the member. The wrap script allows you to specify how to handle get and set operations on each published member: by using the default accessor, by using a custom accessor, or by preventing access.
Published members have a special format, as shown in the following example:
memberName { get: accessStyle set: accessStyle }Put each statement on a line by itself and designate the access style to be one of the following: default, custom, or none.
If a member's access style is default, the wrap script automatically provides the generated class with a member of type MClvalue for storing that value. The member's name is its published name preceded by an m. In our example, the wrap script would provide the wrapped class with a member named mname.
Sometimes a member doesn't really exist as a member of the wrapped class. For instance, in our example, the foundation IntStack class already maintains the height, so it would be wasteful for us to maintain that information in the wrapped class too. For cases such as this, the wrap script allows you to specify a custom access method for a member. If you specify a custom get statement for a member, you must provide a method with the following signature, where memberName represents the appropriate member's name:
UTvalue _Get_memberName() constIn our example, we provide a method called _Get_height that asks its foundation object for the current height. If you specify a custom set method, you must provide a method with the following signature:
void _Set_memberName( const UTvalue& newVal )
If it made sense to set the height of a stack, you could specify that the set accessor of height be custom and provide a method named _Set_height.
You can tell the wrap script to specify an access style of none to handle the case where you do not want to allow get and set operations on members. In our example, height has a set access method of none, causing a fatal error for in any ADL program that attempts to set it.
Each of the protection levels is optional and contains method descriptions. A method description consists of the method's C++ signature, followed by a block of uninterpreted C++ code (set off by === delimiters). The wrap script extracts the signatures and places them in the proper protection level section of the generated header, and places the definition in the generated source file. If you specify the keyword inline, the wrap script places the body of the method in the header too. Specify the keyword ctor to mark an ADL constructor. Marking a method with ctor is equivalent to using the keyword upon in the ADL. The keyword local marks a method as it does in the ADL. ADL subclasses of the wrapped class do not inherit the method, but wrapped subclasses do.
The wrap script exports methods listed in the published section to the ADL as methods with a corresponding name and ADL signature. The following types are the only legal arguments and return types for published methods:
As a special case, you can also have the return type void. It is equivalent to not declaring a return type in the ADL.
Generated with Harlequin WebMaker