[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1 Object Overview

ns-3 is fundamentally a C++ object-based system. By this we mean that new C++ classes (types) can be declared, defined, and subclassed as usual.

Many ns-3 objects inherit from the ns3::Object base class. These objects have some additional properties that we exploit for organizing the system and improving the memory management of our objects:

ns-3 objects that use the attribute system derive from either ns3::Object or ns3::ObjectBase. Most ns-3 objects we will discuss derive from ns3::Object, but a few that are outside the smart pointer memory management framework derive from ns3::ObjectBase.

Let’s review a couple of properties of these objects.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1.1 Smart pointers

As introduced in the ns-3 tutorial, ns-3 objects are memory managed by a reference counting smart pointer implementation, class ns3::Ptr.

Smart pointers are used extensively in the ns-3 APIs, to avoid passing references to heap-allocated objects that may cause memory leaks. For most basic usage (syntax), treat a smart pointer like a regular pointer:

  Ptr<WifiNetDevice> nd = ...;
  nd->CallSomeFunction ();
  // etc.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1.2 CreateObject

As we discussed above in Memory management and class Ptr, at the lowest-level API, objects of type ns3::Object are not instantiated using operator new as usual but instead by a templated function called CreateObject().

A typical way to create such an object is as follows:

  Ptr<WifiNetDevice> nd = CreateObject<WifiNetDevice> ();

You can think of this as being functionally equivalent to:

  WifiNetDevice* nd = new WifiNetDevice ();

Objects that derive from ns3::Object must be allocated on the heap using CreateObject(). Those deriving from ns3::ObjectBase, such as ns-3 helper functions and packet headers and trailers, can be allocated on the stack.

In some scripts, you may not see a lot of CreateObject() calls in the code; this is because there are some helper objects in effect that are doing the CreateObject()s for you.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1.3 TypeId

ns-3 classes that derive from class ns3::Object can include a metadata class called TypeId that records meta-information about the class, for use in the object aggregation and component manager systems:


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1.4 Object Summary

Putting all of these concepts together, let’s look at a specific example: class ns3::Node.

The public header file node.h has a declaration that includes a static GetTypeId function call:

class Node : public Object
{
public:
  static TypeId GetTypeId (void);
  ...

This is defined in the node.cc file as follows:

 
 
TypeId 
Node::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::Node")
    .SetParent<Object> ()
    .AddConstructor<Node> ()
    .AddAttribute ("DeviceList", "The list of devices associated to this Node.",
                   ObjectVectorValue (),
                   MakeObjectVectorAccessor (&Node::m_devices),
                   MakeObjectVectorChecker<NetDevice> ())
    .AddAttribute ("ApplicationList", "The list of applications associated to this Node.",
                   ObjectVectorValue (),
                   MakeObjectVectorAccessor (&Node::m_applications),
                   MakeObjectVectorChecker<Application> ())
    .AddAttribute ("Id", "The id (unique integer) of this Node.",
                   TypeId::ATTR_GET, // allow only getting it.
                   UintegerValue (0),
                   MakeUintegerAccessor (&Node::m_id),
                   MakeUintegerChecker<uint32_t> ())
    ;
  return tid;

Consider the TypeId of an ns-3 Object class as an extended form of run time type information (RTTI). The C++ language includes a simple kind of RTTI in order to support dynamic_cast and typeid operators.

The “.SetParent<Object> ()” call in the declaration above is used in conjunction with our object aggregation mechanisms to allow safe up- and down-casting in inheritance trees during GetObject.

The “.AddConstructor<Node> ()” call is used in conjunction with our abstract object factory mechanisms to allow us to construct C++ objects without forcing a user to know the concrete class of the object she is building.

The three calls to “.AddAttribute” associate a given string with a strongly typed value in the class. Notice that you must provide a help string which may be displayed, for example, via command line processors. Each Attribute is associated with mechanisms for accessing the underlying member variable in the object (for example, MakeUintegerAccessor tells the generic Attribute code how to get to the node ID above). There are also “Checker” methods which are used to validate values.

When users want to create Nodes, they will usually call some form of CreateObject,

  Ptr<Node> n = CreateObject<Node> ();

or more abstractly, using an object factory, you can create a Node object without even knowing the concrete C++ type

  ObjectFactory factory;
  const std::string typeId = "ns3::Node'';
  factory.SetTypeId (typeId);
  Ptr<Object> node = factory.Create <Object> ();

Both of these methods result in fully initialized attributes being available in the resulting Object instances.

We next discuss how attributes (values associated with member variables or functions of the class) are plumbed into the above TypeId.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated on April 21, 2010 using texi2html 1.82.