Let's review the portal classes used so far. Figure 7 shows the classes in the Portal Layer. This diagram does not show all the classes in our example; some other net classes, like RWInetAddr, are discussed in a later chapter.
Of the classes in the picture, the examples we've shown use only RWSocketPortal. You probably didn't realize that the other classes were involved. This is part of the layering philosophy of the net library: you use only what you need, but the other classes are always there, waiting until you need an additional level of power and flexibility. In this case, the hidden concept is a portal and its implementation.
RWPortal is a portable, transport-independent, communications class. It is designed using the interface/implementation paradigm. The interface class, RWPortal, provides a simple interface to the underlying communications channel. It provides a variety of efficient, user friendly functions for reading and writing unbuffered data to and from a communications channel. The implementation base class, RWPortalImpl, is an abstract base class which provides an interface for the operations that an RWPortal needs. The RWPortalImpl is used only by the RWPortal objects which reference it; users of the net library cannot directly access the implementation objects. Classes derived from RWPortalImpl, such as RWSocketPortalImpl, implement the operations defined in the RWPortalImpl base class.
Each RWPortal is associated with one RWPortalImpl located on the heap. The net library uses reference counting so that multiple RWPortal objects can refer to the same underlying implementation object. The RWPortal copy constructor and assignment operator create shallow, lightweight copies through their implementation object. When all the portals that refer to a particular implementation object have gone out of scope, the implementation object's destructor is called (often this closes the communication channel) and the implementation object is deleted from the heap.
The RWPortal interface works well to handle portable communications once a connection is established. Unfortunately, RWPortal cannot handle the non-portable details of the communication, such as making the connection to the server, because the parameters and steps involved in making the connection can vary dramatically from one channel type to another. The net library solves this problem by using channel-specific portal classes, such as RWSocketPortal. These classes inherit from RWPortal, and add constructors and operations specific to their channel type. For example, RWSocketPortal adds constructors which accept socket addresses, and socket-specific functions for operations like returning the underlying RWSocket object or connecting to a specified Internet server.
The channel-specific portal classes do not change the behavior of RWPortal member functions that use inheritance. Indeed, they cannot, since RWPortal has no virtual member functions! For this reason, you can assign a channel-specific portal to an RWPortal without changing the semantics of the portal, as demonstrated in the following example:
RWSocketPortal makeConnection() { RWSocketPortal sp( RWInetAddr(3010,"net.roguewave.com") ); //1 return sp; } main() { RWWinSockInfo info; RWPortal portal = makeConnection(); //2 . . . }
On line //2, an RWSocketPortal is converted to an RWPortal using the copy constructor RWPortal::RWPortal(const RWPortal&). This conversion appears to lose the socket-specific part of the portal by slicing. In fact, it does not: the socket-specific implementation is in the RWSocketPortal object that was constructed, implicitly, on line //1. This conversion does lose the extra interface provided in the RWSocketPortal class. In exchange, subsequent code that uses the portal is independent of the communication channel. Here is a diagram of the objects left after line //2 has been executed.
The portal object has a pointer to an implementation object, which it knows belongs to a class derived from RWPortalImpl. Because our object is an RWSocketPortalImpl, the socket kept as a member object in the implementation is used for reading and writing to the channel. Once the variable portal goes out of scope, its destructor is called. The destructor decrements the reference count of the implementation object. If no other RWPortal objects refer to this implementation object, the object is destroyed. For RWSocketPortalImpl, destroying the object closes the communications channel.
©Copyright 2000, Rogue Wave Software, Inc.
Contact Rogue Wave about documentation or support issues.