Welcome to Scribd, the world's digital library. Read, publish, and share books and documents. See more
Download
Standard view
Full view
of .
Look up keyword
Like this
1Activity
0 of .
Results for:
No results containing your search query
P. 1
External Polymorphism

External Polymorphism

Ratings: (0)|Views: 11|Likes:
Published by newtonapples

More info:

Published by: newtonapples on Mar 12, 2010
Copyright:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as PDF, TXT or read online from Scribd
See more
See less

03/12/2010

pdf

text

original

 
External Polymorphism
An Object Structural Pattern for Transparently Extending C++ Concrete Data TypesChris Cleeland
chris@envision.comEnvision Solutions,St. Louis, MO 63141
Douglas C. Schmidt and Timothy H. Harrison
schmidt@cs.wustl.edu and harrison@cs.wustl.eduDepartment of Computer ScienceWashingtonUniversity, St. Louis, Missouri, 63130This paper appeared in the Proceedings of the 3
r
Pat-tern Languages of Programming Conference, Allerton Park,Illinois,September 4–6, 1996.
1 Intent
Allow C++ classes unrelated by inheritance and/or havingno virtual methods to be treated polymorphically. Theseunrelated classes can be treated in a common manner bysoftware that uses them.
2 Motivation
Workingwith C++ classes from different sources can be dif-ficult. Often an application may wish to “project” commonbehavior on such classes, but is restricted by the classes’existing design. If only the class interface requires adap-tation an obvious solution is to apply an object structuralpattern such as Adapter or Decorator [1]. Occasionally thereare more complex requirements, such as the need to changebothunderlyinginterfaceandimplementation. Insuch cases,classes mayneedtobehaveasiftheyhadacommonancestor.For instance, consider the case where we are debuggingan application constructed using classes from various C++libraries. Itwouldbeconvenienttobeabletoaskanyinstanceto “dump” its state in a human-readable format to a file orconsole display. It would be even more convenient to gatherall live class instances into a collection and iterate over thatcollection asking each instance to dump itself.Since collections are homogeneous, a common base classmust exist to maintain a single collection. Since classes arealready designed,implemented andinuse, however, modify-ing the inheritance tree to introduce a common base class isnot an option– we may not have access to the source, either!In addition, classes in OO languages like C++ may be
con-crete data types
[2], which require strict storage layouts thatcould be compromised by hidden pointers (such as C++’svirtual table pointer). Re-implementing these classes with acommon, polymorphic, base class is not feasible.Thus, projecting common behavior on unrelated classesrequires the resolution of the following forces constrainingthe solution:1.
Space efficiency
– The solution must not constrain thestorage layout of existing objects. In particular, classesthat have no virtual methods (
i.e.,
concrete data types)must not be forced to add a virtual table pointer.2.
Polymorphism
– All library objects must be accessedin a uniform, transparent manner. In particular, if newclasses are included into the system, we won’t want tochange existing code.Consider the following example using classes from theACE network programming framework [3]:
1. SOCK_Acceptor acceptor; // Global storage2.3. int main (void) {4. SOCK_Stream stream; // Automatic storage5. INET_Addr *addr =6. new INET_Addr // Dynamic storage.7. ...
The
SOCK Stream
,
SOCK Acceptor
, and
INET Addr
classes are all concrete data types since they don’t all in-herit from a common ancestor and/or they don’t contain vir-tual functions. If during a debugging session an applicationwanted to examine the state of all live ACE objects at line 7,we might get the followingoutput:
Sock_Stream::this = 0x47c393ab, handle_ = {-1}SOCK_Acceptor::this = 0x2c49a45b, handle_ = {-1}INET_Addr::this = 0x3c48a432,port_ = {0}, addr_ = {0.0.0.0}
An effective way to project the capability to dump stateonto these class without modifying their binary layout is touse the
External Polymorphism pattern.
This pattern con-structs a parallel, external inheritance hierarchy that projectspolymorphic behavior onto a set of concrete class that neednot be related by inheritance. The following OMT diagramillustrates how the External Polymorphism pattern can beused to create the external, parallel hierarchy of classes:1
 
Collection
Dumpable 
 
dump()
 
ConcreteDumpable<
AnyType 
>
 
dump()AnyType* this_ 
 
instance->printTo()SignatureAdapter<
AnyType 
>
 
::dump<SOCK_Stream>(instance)::dump<INET_Addr>(instance)
 
delegates
NOTE
:SignatureAdapter is the name ofthe role played by the assorted templatefunctions; it is not really a class.
As shown in the figure, we define an abstract class(
Dumpable
) having the desired
dump
interface. Theparameterized class
ConcreteDumpable
 
inheritsfrom
Dumpable
and contains a pointer to an instanceof its parameter class,
e.g.
,
SOCK Stream
. In ad-dition, it defines a body for
dump
that delegates tothe
dump
 
template function (shown in the figure asthe
SignatureAdapter
 
pseudo-class and parame-terized over the concrete class). The
dump
templatefunction calls the corresponding implementation methodon the concrete class,
e.g.
,
SOCK Stream::dump
or
INET Addr::printTo
.Using the External Polymorphism pattern, it is now pos-sible to collect
Dumpable
instances and iterate over them,calling the
dump
method uniformly on each instance. Notethat the original ACE concrete data types need not change.
3 Applicability
Use the External Polymorphism pattern when:1. Yourclass librariescontainconcrete data typesthatcan-not inherit from a common base class containingvirtualmethods; and2. The behavior of your class libraries or applications canbe simplified significantly if you can treat all objects ina polymorphicmanner.Do not use the External Polymorphism pattern when:1. Your class libraries already contain abstract data typesthat inherit from common base classes and contain vir-tual methods; or2. Your programming language or programming environ-mentallowsmethodstobeaddedtoclassesdynamically.
4 Structure and Participants
Client
Common 
 
request()
ConcreteCommon<
ConcreteType 
>
 
request()ConcreteType* this_ 
 
instance->specificRequest()SignatureAdapter<
ConcreteType 
>
 
::request<Concrete1>(instance)::request<Concrete2>(instance)
 
delegates
NOTE
:SignatureAdapter is the name ofthe role played by the assorted templatefunctions; it is not really a class.
 
Common
(
Dumpable
)
This abstract class forms the base of the exter-nal, parallel hierarchy and defines the interface(s)whose behaviors will be polymorphically pro- jected and used by clients.
 
ConcreteCommon
 
ConcreteType
 
(
ConcreteDumpable
)
This parameterized subclass of 
Common
imple-mentstheinterface(s) definedin
Common
. A typi-cal implementationwill simply forwardthe call tothe appropriate
SignatureAdapter
templatefunction.
 
SignatureAdapter::request
 
ConcreteType
 
(::dump
 
)
The template function adapter forwards re-quests to the object. In some cases,
e.g.
,where the signature of 
specificRequest
is consistent, this feature may not be needed.However, if 
specificRequest
has differ-ent signatures within several
Concrete
classes,the SignatureAdapter can be used to insulate
ConcreteCommon
from the differences.
 
ConcreteType
The
ConcreteType
classes dene
specificRequest
operationsthatperformthedesired tasks. Although
Concrete
classes neednot be related by inheritance, the External Poly-morphism pattern allows you to treat all or someof their methods polymorphically.
5 Collaborations
The External Polymorphismpatternis typicallyused byhav-inganexternal clientmake requeststhroughthepolymorphic2
 
Common*
. The following is an interaction diagram for thiscollaboration.
Common
request 
 
operationConcreteCommonConcreteTyperequestrequestSignatureAdapter::requestspecificRequest
Many applications of the External Polymorphism patternmaintain a collectionof objects over which the program iter-ates, treating all collected objects uniformly. Although thisis not strictlypart of the pattern, it is a common use-case thatbears mentioning.
6 Consequences
The External Polymorphism pattern has the followingbene-fits:
 
Transparent 
– Classes that were not originallydesignedtoworktogethercanbeextendedrelativelytransparentlyso they can be treated polymorphically. In particular,the object layout of existing classes need not change byadding virtual pointers.
 
Flexible
– It’s possible to polymorphically extend non-extensible data types such as
int
or
double
whenthe pattern is implemented in a language supportingparameterized types (
e.g.,
C++ templates).
 
Peripheral
– Because the pattern establishes itself onthe fringes of existing classes, it’s easy to use condi-tional compilation to remove all trace of this pattern.This feature is particularly useful for systems that usethe External Polymorphism pattern only for debuggingpurposes.This pattern has the followingdrawbacks:
 
 Instability
The methods in the
Common
and
ConcreteCommon
must track changes to methods inthe
Concrete
classes.
 
 Inefficient 
– Extra overhead due to multiple forwardingfrom virtual methods in the
ConcreteCommon
ob- ject to the corresponding methods in the
Concrete
object. However, judicious use of inline (
e.g.
, within
SignatureAdapter
and
Concrete
) can reducethis overhead to a single virtual method dispatch.There is another consideration when using this pattern:
 
Possibility of inconsistency
– Externally Polymorphicmethods are not accessible through pointers to the con-crete classes,
e.g.,
using the example in Section 2it’s not possible to access
dump
through a pointer to
SOCK Stream
. In addition,it is not possible to accessother methodsfrom the concrete class througha pointerto
ConcreteCommon
.
7 Implementation
The followingissues arise when implementing this pattern.
 
 Arguments to
specificRequest
.
Projecting poly-morphic behavior will usually require adaptation of thesignatures of the various
specificRequest
s. Thiscan be complicated when, forinstance, some require ar-guments, whereas othersdo not. The implementer mustdecide whether to expose those arguments in the poly-morphic interface or to insulate the client from them.
 
Where does the code go?
As mentioned in Section 6,the external class hierarchy must be maintained in par-allel with the original classes. The implementer mustcarefully select the source files in which co-dependentcode, such as signature adaptation, is implemented.
 
 External Polymorphism is not an Adapter.
The in-tent of the Adapter pattern is to
convert 
an interfaceto something usable by a client. External Polymor-phism, on the other hand, focuses on providing anew base for existing interfaces. A “serendipitous”use of External Polymorphism would find all signa-tures for
specificRequest
identical across all dis-parate classes, and thus not require the use of 
Signa-tureAdapter 
; it is in this situation where it is most ap-parent that External Polymorphism is not an Adapter.
8 Sample Code
To lookat an example implementation, recall the motivatingscenario: there are classes whose assistance we wishtoenlistto create a flexible debugging environment. This implemen-tation uses the External Polymorphism pattern to define amechanism by which all participatingobjects (1) can be col-lected in a central “in-memory” object collectionand (2)candump their state upon request.The
Dumpable
class forms the base of the hierarchy anddefines thedesiredpolymorphicinterface which, inthiscase,is for dumping:
class Dumpable{public:Dumpable (const void *);// This pure virtual method must be// implemented by a subclass.virtual void dump (void) const = 0;};
ObjectCollection
is the
client 
–a simple collectionthat holds handles to objects. The class is based on the STL
vector
class [4].
class ObjectCollection : public vector<Dumpable*>{public:// Iterates through the entire set of// registered objects and dumps their state.void dump_objects (void);};
3

You're Reading a Free Preview

Download
scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->