# HG changeset patch # User Craig Dowell # Date 1228524569 28800 # Node ID 654eed5f3ad03c04c2bcfb6852b5b4ae94260bc6 # Parent cfafbc337dbbd583a6fa926dc26f07c9358210b3# Parent 44d4f4d768dd3e097835f529da85763f7be219ad branch merge diff -r cfafbc337dbb -r 654eed5f3ad0 doc/manual/manual.texi --- a/doc/manual/manual.texi Fri Dec 05 16:49:05 2008 -0800 +++ b/doc/manual/manual.texi Fri Dec 05 16:49:29 2008 -0800 @@ -81,18 +81,21 @@ * Random variables:: * Callbacks:: * Attributes:: +* Object model:: * RealTime:: +* Emulation:: * Packets:: * Sockets APIs:: * Node and Internet Stack:: * TCP:: * Routing overview:: -* Troubleshooting +* Troubleshooting:: @end menu @include random.texi @include callbacks.texi @include attributes.texi +@include objects.texi @include realtime.texi @include emulation.texi @include packets.texi diff -r cfafbc337dbb -r 654eed5f3ad0 doc/manual/objects.texi --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/manual/objects.texi Fri Dec 05 16:49:29 2008 -0800 @@ -0,0 +1,281 @@ +@c ======================================================================== +@c ns-3 Object model +@c ======================================================================== + +@node Object model +@chapter Object model + +@command{ns-3} is fundamentally a C++ object system. Objects can +be declared and instantiated as usual, per C++ rules. ns-3 also +adds some features to traditional C++ objects, as described below, +to provide greater functionality and features. This manual chapter +is intended to introduce the reader to the ns-3 object model. + +This section describes the C++ class design for ns-3 objects. In brief, +several design patterns in use include classic object-oriented design +(polymorphic interfaces and implementations), separation of interface +and implementation, the non-virtual public interface design pattern, +an object aggregation facility, and reference counting +for memory management. Those familiar with component models such +as COM or Bonobo will recognize elements of the design in the +ns-3 object aggregation model, although +the ns-3 design is not strictly in accordance with either. + +@node Object-oriented behavior +@section Object-oriented behavior + +C++ objects, in general, provide common object-oriented capabilities +(abstraction, encapsulation, inheritance, and polymorphism) that are part +of classic object-oriented design. ns-3 objects make use of these +properties; for instance: + +@verbatim +class Address +{ +public: + Address (); + Address (uint8_t type, const uint8_t *buffer, uint8_t len); + Address (const Address & address); + Address &operator = (const Address &address); + ... +private: + uint8_t m_type; + uint8_t m_len; + ... +}; +@end verbatim + +@node Object base classes +@section Object base classes + +There are two special base classes used in ns-3. Classes that inherit +from these base classes can instantiate objects with special properties. +These base classes are: +@itemize @bullet +@item @code{class Object} +@item @code{class ObjectBase} +@item @code{class RefCountBase} +@end itemize +It is not required that ns-3 objects inherit from these class, but +those that do get special properties. Classes deriving from +@code{class Object} get the following properties. +@itemize @bullet +@item the ns-3 type and attribute system (see @ref{Attributes}) +@item a smart-pointer reference counting system (class Ptr) +@item an object aggregation system +@end itemize + +Classes that derive from @code{class ObjectBase} get the first two +properties above, but do not get smart pointers. Classes that +derive from @code{class RefCountBase} get only the smart-pointer +reference counting system. + +In practice, @code{class Object} is the variant of the three above that +the ns-3 developer will most commonly encounter. + +@node Memory management and class Ptr +@section Memory management and class Ptr + +Memory management in a C++ program is a complex process, and is +often done incorrectly or inconsistently. We have settled on +a reference counting design described as follows. + +All objects using reference counting maintain an internal reference +count to determine when an object can safely delete itself. +Each time that a pointer is obtained to an interface, the object's +reference count is incremented by calling @code{Ref()}. +It is the obligation of the +user of the pointer to explicitly @code{Unref()} the pointer when done. +When the reference count falls to zero, the object is deleted. + +@itemize @bullet +@item When the client code obtains a pointer from the object itself +through object creation, or via QueryInterface, it does not have +to increment the reference count. +@item When client code obtains a pointer from another source (e.g., +copying a pointer) it must call @code{Ref()} to increment the +reference count. +@item All users of the object pointer must call @code{Unref()} to +release the reference. +@end itemize + +The burden for calling @code{Unref()} is somewhat relieved by the +use of the reference counting smart pointer class described below. + +Users using a low-level API who wish to explicitly allocate +non-reference-counted objects on the heap, using operator new, +are responsible for deleting such objects. + +Packet objects are handled differently (without reference +counting); their design is described in @ref{Packets}. + +@subsection Reference counting smart pointer (Ptr) + +Calling @code{Ref()} and @code{Unref()} all the time would be cumbersome, +so ns-3 provides a smart pointer @code{class Ptr} similar to +@code{Boost::intrusive_ptr}. +This smart-pointer class assumes that the underlying type provides +a pair of Ref and Unref methods that are expected to increment and +decrement the internal refcount of the object instance. + +This implementation allows you to manipulate the smart pointer +as if it was a normal pointer: you can compare it with zero, +compare it against other pointers, assign zero to it, etc. + +It is possible to extract the raw pointer from this +smart pointer with the GetPointer and PeekPointer methods. + +If you want to store a newed object into a smart pointer, +we recommend you to use the CreateObject template functions +to create the object and store it in a smart pointer to avoid +memory leaks. These functions are really small convenience +functions and their goal is just is save you a small +bit of typing. + +@node CreateObject and Create +@subsection CreateObject and Create + +Objects in C++ may be statically, dynamically, or automatically created. +This holds true for ns-3 also, but some objects in the system +have some additional frameworks +available. Specifically, reference counted objects are usually +allocated using a templated Create or CreateObject method, as follows. + +For objects deriving from @code{class Object}: +@verbatim + Ptr device = CreateObject (); +@end verbatim + +For objects deriving from @code{class RefCountBase}, or other +objects that support usage of smart pointer (e.g., the ns-3 Packet class), +a templated helper function is available and recommended to be used: +@verbatim + ns3::Ptr b = ns3::Create (); +@end verbatim +This is simply a wrapper around operator new that correctly handles +the reference counting system. + +@node Aggregation +@subsection Aggregation + +The ns-3 object aggregation system is motivated in strong part by +a recognition that a common use case for ns-2 has been the use of +inheritance and polymorphism to extend protocol models. For instance, +specialized versions of TCP such as RenoTcpAgent derive from (and override +functions from) class TcpAgent. + +However, two problems that have arisen in the ns-2 model are downcasts +and ``weak base class.'' Downcasting refers to the procedure of using +a base class pointer to an object and querying it at run time to +find out type information, used to explicitly cast the pointer to +a subclass pointer so that the subclass API can be used. +Weak base class refers to the problems that arise when a class +cannot be effectively reused (derived from) because it lacks necessary +functionality, leading the developer to have to modify the +base class and causing proliferation of base class API calls, some +of which may not be semantically correct for all subclasses. + +ns-3 is using a version of the query interface design pattern +to avoid these problems. This design is based on elements of the +@uref{http://en.wikipedia.org/wiki/Component_Object_Model,,Component Object Model} +and @uref{http://en.wikipedia.org/wiki/Bonobo_(component_model),,GNOME Bonobo} +although full binary-level compatibility of replaceable components +is not supported and we have tried to simplify the syntax and impact +on model developers. + +@subsubsection Aggregation example + +@code{class Node} is a good example of the use of aggregation in ns-3. +Note that there are not derived classes of Nodes in ns-3 such as +class InternetNode. Instead, components (protocols) are aggregated to +a node. Let's look at how some Ipv4 protocols are added to a node. + +@verbatim +static void +AddIpv4Stack(Ptr node) +{ + Ptr ipv4 = CreateObject (); + ipv4->SetNode (node); + node->AggregateObject (ipv4); + Ptr ipv4Impl = CreateObject (); + ipv4Impl->SetIpv4 (ipv4); + node->AggregateObject (ipv4Impl); +} +@end verbatim + +Note that the Ipv4 protocols are created using @code{CreateObject()}. +Then, they are aggregated to the node. In this manner, the Node base +class does not need to be edited to allow users with a base class Node +pointer to access the Ipv4 interface; users may ask the node for a pointer +to its Ipv4 interface at runtime. How this is done is seen in the next +subsection. + +@subsubsection GetObject example +GetObject is a type-safe way to achieve a safe downcasting +and to allow interfaces to be found on an object. + +Consider a node pointer @code{m_node} that points to a Node object +with an implementation of IPv4. The client code wishes to configure +a default route. To do so, it must access an object within +the node that has an interface to the IP forwarding configuration. +It performs the following: +@verbatim + Ptr ipv4 = m_node->GetObject (); +@end verbatim + +If the node in fact does not have an Ipv4 object aggregated to it, then +the method will return null. Therefore, it is good practice to check +the return value from such a function call. If successful, the user can +now use the Ptr to the Ipv4 object that was previously aggregated to +the node. + +@subsubsection Summary +To summarize, two benefits that we expect to leverage from this are as follows: +@itemize @bullet +@item @strong{Encapsulation:} By separating interface from implementation, +it permits +implementors to replace elements of the protocol stack while remaining +compliant with client code that supports the same interface. For +example, one type of node may include native ns-3 models of protocols, +while another may be a port of a Linux stack, and both may be accessed +by the same base class node pointer. +@item @strong{Aggregation:} AggregateObject allows for aggregation of +objects at +run time. For instance, an existing Node object may have an ``Energy Model'' +object aggregated to it at run time (without modifying +and recompiling the node class). An existing model (such as a wireless +net device) can then later "GetObject" for the energy model and act +appropriately if the interface has been either built in to the underlying +Node object or aggregated to it at run time. +@end itemize + +We hope that this mode of programming will require much less +need for developers to modify the @code base classes or libraries. + +@node Downcasting +@section Downcasting + +A question that has arisen several times is, "If I have a base class +pointer (Ptr) to an object and I want the derived class pointer, should +I downcast (via C++ dynamic cast) to get the derived pointer, or should +I use the object aggregation system to @code{GetObject<> ()} to find +a Ptr to the interface to the subclass API?" + +The answer to this is that in many situations, both techniques will work. +ns-3 provides a templated function for making the syntax of Object +dynamic casting much more user friendly: +@verbatim +template +Ptr +DynamicCast (Ptr const&p) +{ + return Ptr (dynamic_cast (PeekPointer (p))); +} +@end verbatim + +DynamicCast works when the programmer has a base type pointer and is +testing against a subclass pointer. GetObject works when looking for +different objects aggregated, but also works with subclasses, in the same +way as DynamicCast. If unsure, the programmer should use GetObject, as it +works in all cases. If the programmer knows the class hierarchy of the +object under consideration, it is more direct to just use DynamicCast.