Appendix B Creating Wrapped Classes
Frequently, the foundation classes that we want to wrap have an inheritance relationship. Let's suppose that we want to wrap a class called PrintableIntStack. This new class is a subclass of the IntStack class that we discuss in the example in Section 1.2.2, and it adds the method
getPrintString to its interface, which returns a string that describes the stack.
Using only the features described in the previous section, we would have to create a new wrap file
that includes all of the wrap description of the existing DSintStack wrapped class referred to in Section 1.1, but which has PrintableIntStack as its foundation class and getPrintString as a published method. As you might expect, this leads to maintenance nightmares, especially since wrapped classes often have more methods and members than DSintStack does.
Let's look at this example two ways: first without inheritance and then with inheritance.
notice ===================================================================== /* * $Header: /mit/ceci/1/aybee/devl/doc/firstRel/RCS/ DSprintableIntStackROsansInheritance.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: DSprintableIntStack module: ExampleModule abstract: false header ==================================================================== #include <PrintableIntStack.h> /* * PrintableIntStack.h hypothetically includes something like... * * #include <PrintableIntStack.h> * * class PrintableIntStack: public IntStack * { * public: * char* getPrintString(); * }; * */ ====================================================================== source ====================================================================== #include <control/EXmodule.h> #include <control/DSprintableIntStackRO.h> #include <adl/ERsemantic.h> ====================================================================== codeFragments { constructor ====================================================================== mpWrapped = new PrintableIntStack; ====================================================================== } 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(); ====================================================================== UTstring GetPrintString( ) ====================================================================== /* effects: puts newTop on the top of the stack */ return mpWrapped->GetPrintString(); ====================================================================== }
notice ====================================================================== /* * * $Header: /mit/ceci/1/aybee/devl/doc/firstRel/RCS/DSprintableIntStackRO.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: PrintableIntStack wrapped: DSprintableIntStack module: ExampleModule abstract: false header ====================================================================== #include <PrintableIntStack.h> /* * PrintableIntStack.h hypothetically includes something like... * * #include <PrintableIntStack.h> * * class PrintableIntStack: public IntStack * { * public: * char* getPrintString(); * }; * */ ====================================================================== source ====================================================================== #include <control/EXmodule.h> #include <control/DSprintableIntStackRO.h> #include <adl/ERsemantic.h> ====================================================================== superclasses { DSintStack } codeFragments { constructor ====================================================================== mpWrapped = new PrintableIntStack; ====================================================================== } methods { published: UTstring GetPrintString( ) ====================================================================== /* effects: puts newTop on the top of the stack */ return mpWrapped->GetPrintString(); ====================================================================== }
The wrap script uses each superclass name listed to find the corresponding description. It looks for a file named "superclassNameRO.wrp" somewhere in the wrap path. In our example, the wrapper looks for DSintStackRO.wrp. The wrapper ensures that the ADL run-time engine thinks of each listed class as a superclass of the given class.
For example, DSprintableIntStack is a subclass of DSintStack. Their foundation classes are
PrintableIntStack and IntStack, respectively, so PrintableStack must be a subclass of IntStack. The code that the wrap script generates to check the pointer types is as follows:
(IntStack*) tempPtr = (PrintableIntStack*) NULL;
The contents of constructor and constructorFromFoundation are not inherited. This is in keeping with the C++ treatment of constructors, and it is partly attributable to the special meaning of the mpWrapped member. No matter how many wrapper descriptions a class inherits from, it has only one mpWrapped member. The wrap script provides the preConstructor and wrappedIsReady fragments (which are inherited by concatenation in the proper order) to allow a superclass to initialize its members before and after mpWrapped is constructed and ready for operation.
In an effort to cut down on the size of wrapped classes, the wrapper does not completely fill out the class description for abstract, non-adlSubclassable classes since no instances of them will ever be created. We call those ANAS classes. In addition, it does not include all of the inherited header and source declarations. Unfortunately, hidden in the source sections are the includes of the generated header file and the include of the module in which the class is generated. Instead of including the whole source section to provide the correct include statements, the wrapper uses some heuristics to find and include only the needed include directives.
It is possible that the wrap script's attempted short cuts will be too effective and break something. The optional wrap directive ANAScuts: boolean keeps the wrapper from taking short cuts in any class for which it is set to true, as well as in all of its subclasses. This feature is provided only as an escape hatch in the unlikely event that the heuristics fail. If you have to use this escape hatch, please let us know.
Generated with Harlequin WebMaker