further ns-3-obj changes
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 4.7 KiB |
BIN
doc/tutorial/oneobj.png
Normal file
BIN
doc/tutorial/oneobj.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
@@ -36,6 +36,8 @@ you old-timers) cable. This topology is shown below.
|
||||
@sp 1
|
||||
@center @image{pp,,,,png}
|
||||
|
||||
@cindex CreateObject
|
||||
@cindex InternetNode
|
||||
We have provided a file for you in the @code{tutorial}
|
||||
directory called @code{tutorial-point-to-point.cc}. You should now be
|
||||
familiar enough with the system to pick out fairly easily what has been
|
||||
@@ -1065,6 +1067,7 @@ thorougly understand what we've gone over so far.
|
||||
@node Object-Model
|
||||
@chapter Object Model
|
||||
|
||||
@cindex Object Model
|
||||
There are two distinctly different meanings associated with the term Object
|
||||
Model. The first speaks to the implementation of an object system --- a system
|
||||
view; and the second speaks to the application programming interface (classes
|
||||
@@ -1075,12 +1078,18 @@ associated object model that describes how objects are laid out in memory,
|
||||
how virtual functions work, how inheritance is implemented, constructor and
|
||||
destructor execution ordering, template instantiation, etc.
|
||||
|
||||
@cindex API
|
||||
@cindex DOM
|
||||
@cindex Document Object Model
|
||||
In the case of the application view, the Document Object Model is a good
|
||||
example. In the words of W3C, the Document Object Model (DOM) is an
|
||||
application programming interface (API) for HTML and XML documents. It defines
|
||||
the logical structure of documents and the way a document is accessed and
|
||||
manipulated.
|
||||
|
||||
@cindex API
|
||||
@cindex COM
|
||||
@cindex Component Object Model
|
||||
The Component Object Model (COM) from Microsoft actually spans both meanings
|
||||
of the term and extends further into policy statements. From a system
|
||||
perspective, COM specifies an interface definition language, the layout of
|
||||
@@ -1091,6 +1100,7 @@ Interfaces as well as functions such as CoCreateInstance and various
|
||||
threading models. The COM specification extends to policy by disallowing
|
||||
implementation inheritance.
|
||||
|
||||
@cindex Feynman
|
||||
The @command{ns-3} object model takes the C++ language (system level) object
|
||||
model as its basis, and extends that model by providing an API for software
|
||||
componentry. You may find terms like Component, Interface and QueryInterface
|
||||
@@ -1122,8 +1132,9 @@ superiority of one mechanism or another. What we will do is provide
|
||||
convenience functions that we think will make creating and managing simulation
|
||||
objects easier.
|
||||
|
||||
@cindex CreateObject
|
||||
Previously, you have seen objects created using the template function
|
||||
@code{Create} as in the following example:
|
||||
@code{CreateObject} as in the following example:
|
||||
|
||||
@verbatim
|
||||
Ptr<Node> n0 = CreateObject<InternetNode> ();
|
||||
@@ -1131,25 +1142,27 @@ Previously, you have seen objects created using the template function
|
||||
|
||||
This line of code, while it may be unfamiliar to some, is pure C++. If you
|
||||
were to look in the header file ptr.h, you would find the following definition
|
||||
of the @code{Create} template.
|
||||
of the @code{CreateObject} template.
|
||||
|
||||
@verbatim
|
||||
template <typename T>
|
||||
Ptr<T> Create (void)
|
||||
Ptr<T> CreateObject (void)
|
||||
{
|
||||
T *obj = new T ();
|
||||
Ptr<T> p = obj;
|
||||
obj->Unref ();
|
||||
Ptr<T> p = Ptr<T> (new T (), false);
|
||||
p->SetTypeId (T::GetTypeId ());
|
||||
return p;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
@cindex template
|
||||
As you can see, this template creates objects of type @code{T} using the
|
||||
operator @code{new}. Its a little harder to find the corresponding delete ---
|
||||
it's in the file @code{object.cc} inside the method @code{Object::MaybeDelete},
|
||||
but when that @code{Ptr} which you see above goes out of scope it will call
|
||||
@code{Unref} and ultimately the C++ @code{delete} operator will be called.
|
||||
|
||||
@cindex new
|
||||
@cindex delete
|
||||
The ns-3 system uses the C++ @code{new} and @code{delete} operators, so there
|
||||
is really no reason that you as a user of the ns-3 system are forbidden from
|
||||
using these or any other C++ mechanism. If you so desire, you can take on
|
||||
@@ -1163,6 +1176,7 @@ operators and call methods like any C++ object as in the following example:
|
||||
delete obj;
|
||||
@end verbatim
|
||||
|
||||
@cindex model
|
||||
You, as a competent model author, are encouraged to use whatever methods you
|
||||
think are appropriate in your private code. Remember, however, that the
|
||||
public ns-3 APIs do use smart pointers to pass objects around in an effort to
|
||||
@@ -1179,13 +1193,20 @@ level magic going on in ns-3. Ns-3 components and interfaces are C++ objects
|
||||
just like any other object and our object model is simply a collection of APIs
|
||||
built on the normal C++ object model.
|
||||
|
||||
@section Interfaces
|
||||
@cindex Interface
|
||||
@cindex Abstract Data Type
|
||||
@cindex ADT
|
||||
@cindex Abstract Base Class
|
||||
@cindex ABC
|
||||
@section Interface
|
||||
There are many different ideas floating around of what exactly the term
|
||||
@emph{interface} means. Originally an interface just meant a communication
|
||||
boundary between two entities. As the concepts of object oriented programming
|
||||
(OOP) were surfacing in the 1980s, the term interface was applied to the
|
||||
collection of access methods for the modular entities that were being defined.
|
||||
|
||||
@cindex OOP
|
||||
@cindex Object Oriented Programming
|
||||
Two distinct approaches developed regarding specifying access mechanisms for
|
||||
objects. The OOP purists were very concerned about object reuse and were led
|
||||
to Abstract Data Types (ADT). These were eventually implemented in the case
|
||||
@@ -1202,6 +1223,7 @@ derived classes. [@dots{}] Some classes, such as class @strong{Shape},
|
||||
represent abstract concepts for which objects cannot exist.''
|
||||
@end quotation
|
||||
|
||||
@cindex PIMPL
|
||||
@command{Ns-3} does not pick and enforce a particular approach. In
|
||||
@command{ns-3} an interface is determined completely by a class declaration
|
||||
just as any C++ object interface is declared. If you think of an object as
|
||||
@@ -1214,30 +1236,37 @@ declare its methods virtual. If you like to use the PIMPL idiom, again, feel
|
||||
free. If you want to use any combination of these techniques, feel free.
|
||||
We make no restrictions.
|
||||
|
||||
@cindex API
|
||||
When we speak of an ns-3 interface, we do not worry about interface definition
|
||||
languages, or pure virtual classes, or registries we just think about C++
|
||||
object declarations and their associated methods. When we instantiate an
|
||||
@command{ns-3} interface, it is the C++ object model that dictates how that
|
||||
object declarations and their associated methods. We tend to think of
|
||||
interfaces to objects as simply a private or public API. When we instantiate
|
||||
an @command{ns-3} interface, it is the C++ object model that dictates how that
|
||||
object is brought into existence. When a method is called on an @command{ns-3}
|
||||
Interface, it is the C++ object model that dictates how that method is
|
||||
dispatched.
|
||||
|
||||
The only difference between a vanilla C++ object and an ns-3 object with a
|
||||
specifically defined interface, is that an object acting as an ns-3 interface
|
||||
must inherit from the base class Object. This inheritance gives the Object
|
||||
a very useful capability conceptually similar to a COM Interface.
|
||||
We do, however, provide a base class that endows vanilla C++ objects with
|
||||
capabilities that can be seen as conceptually similar to those provided by
|
||||
Microsoft Component Model @emph{Interfaces}.
|
||||
|
||||
@section The Ns-3 Interface and GetObject
|
||||
@section The Ns-3 Object and GetObject
|
||||
@cindex Component Object Model
|
||||
One thing that Microsoft arguably got right in the Component Object Model was
|
||||
the idea of Interface aggregation and discovery via QueryInterface. We have
|
||||
embraced these ideas in @command{ns-3}. This was done primarily to address a
|
||||
common problem in large software systems. A good example of this problem
|
||||
happens in the @command{ns-3} Node class.
|
||||
|
||||
@cindex OOP
|
||||
@cindex weak base class
|
||||
@cindex base class bloat
|
||||
@cindex Swiss Army Knife class
|
||||
@cindex Node
|
||||
If one were to take the standard OOP view of specializing a @code{Node} into
|
||||
an internet host, for example, one would typically inherit from the @code{Node}
|
||||
base class and include functionality to implement such things as internet
|
||||
routing and a TCP / IP protocol stack. Other types of @code{Node}s might
|
||||
routing and a TCP/IP protocol stack. Other types of @code{Node}s might
|
||||
inherit from the node class and specialize in different ways, or further
|
||||
specialize the internet host class, treating it as a base class. This can
|
||||
result in a complicated inheritance tree in which some specializations are
|
||||
@@ -1264,16 +1293,18 @@ everything into the base class and destroying much of the encapsulation which
|
||||
is a hallmark of the object oriented approach.
|
||||
|
||||
@subsection Interface Composition
|
||||
@cindex Node
|
||||
There is a completely different way to address the Node specialization
|
||||
problem. Instead of approaching the situation using inheritance, one can
|
||||
look at the problem as one of composition. We can look at the @code{Node}
|
||||
class as a container of sorts that holds other objects. In this case, the
|
||||
objects would be instances of the classes implementing the internetwork
|
||||
routing code, or the TCP / IP protocol stack described above. This approach
|
||||
routing code, or the TCP/IP protocol stack described above. This approach
|
||||
preserves the encapsulation and solves the weak base class, base class bloat
|
||||
and fragile base class problems; but the question of method dispatch
|
||||
immediately comes to mind.
|
||||
|
||||
@cindex delegation
|
||||
In many systems, @emph{delegation} is used. The base class, @code{Node},
|
||||
in this approach would provide methods that simply forward to the objects
|
||||
implementing the desired functionality. This situation clearly does not
|
||||
@@ -1284,27 +1315,33 @@ fundamental problems are still present. What is really needed is a way
|
||||
to compose objects but at the same time keep the interfaces to those
|
||||
objects separated.
|
||||
|
||||
@cindex aggregation
|
||||
Composition, usually called @emph{aggregation}, along with runtime Interface
|
||||
discovery is the solution that Microsoft originally championed and that
|
||||
@command{ns-3} has adopted --- albeit with many simplifications and a few name
|
||||
changes.
|
||||
|
||||
@subsection Objects and Interfaces
|
||||
@cindex COM
|
||||
@cindex QueryInterface
|
||||
Now that we have mentioned Microsoft COM and are almost obligated to mention
|
||||
the terms Interface and QueryInterface. For those familiar with COM, loosely
|
||||
speaking, QueryInterface is to COM as GetObject is to @command{ns-3}.
|
||||
The analogy, while good conceptually, is superficial from an implementation
|
||||
point of view.
|
||||
|
||||
@cindex Node
|
||||
Addressing our current example of a @code{Node}, generically speaking, each
|
||||
node needs to aggregate an object that will implement internetwork routing
|
||||
and TCP/IP. The system will need to provide a mechanism for locating the
|
||||
aggregated objects and allow a client to discover them.
|
||||
|
||||
@cindex aggregation
|
||||
@cindex Object
|
||||
These aggregated objects have interfaces in the C++ sense of collections of
|
||||
method signatures. In @command{ns-3}, when objects are capable of
|
||||
participating in this aggregation process, they are called @command{ns-3}
|
||||
@code{Objects}. @code{Object}s receive the functionality required for this
|
||||
@code{Objects}. @code{Objects} receive the functionality required for this
|
||||
participation by inheriting from the @command{ns-3} base class @code{Object}.
|
||||
|
||||
Note well that when we write the word @code{Object} (note the uppercase 'O' in
|
||||
@@ -1324,7 +1361,7 @@ Once an object has inherited from class @code{Object} it has the ability to
|
||||
also means that it can provide a service to @emph{discover} other objects in
|
||||
its aggregation via the method @code{GetObject}.
|
||||
|
||||
|
||||
@cindex base class
|
||||
Technically, the class named @code{Object} is simply a base class that you
|
||||
will inherit from if you want your @code{Objects} to support aggregation and
|
||||
discovery. Many systems have a base class that implements common
|
||||
@@ -1340,13 +1377,16 @@ In ns-3, you should associate inheritance from the class named @code{Object}
|
||||
with promotion of an object to the status of some locatable @code{Object}
|
||||
rather than with the form of the class declaration.
|
||||
|
||||
@cindex COM
|
||||
@cindex CORBA
|
||||
@cindex ORBit
|
||||
For those of you unfamiliar with Microsoft COM, CORBA or ORBit, this might
|
||||
sound obvious. For those of with such a background, the point we are making
|
||||
is that there is no such thing in @command{ns-3} as a separate Interface
|
||||
declaration, no such thing as an Interface Definiition Language, no such thing
|
||||
as a UUID or GUID, etc. In @command{ns-3} we just work with C++ objects that
|
||||
may be given some very useful abilities by inheriting from the @command{ns-3}
|
||||
base class @code{Object}. @command{Ns-3} @code{Object}s are not required to
|
||||
base class @code{Object}. @command{Ns-3} @code{Objects} are not required to
|
||||
inherit from classes composed of pure virtual methods in order to define an
|
||||
Interface. It's all really just ``plain old C++.''
|
||||
|
||||
@@ -1354,13 +1394,17 @@ To summarize, when you instantiate an object that inherits from the
|
||||
@code{Object} class, you will have a C++ object that has four important
|
||||
properties:
|
||||
|
||||
@cindex AggregateObject
|
||||
@cindex GetObject
|
||||
@itemize @bullet
|
||||
@item The @code{Object} has a C++ interface defined by the collection of method signatures in its inheritance tree;
|
||||
@item The @code{Object} has some way to identify its underlying class uniquely;
|
||||
@item The @code{Object} is a kind of container that has the ability to aggregate other @code{Object}s using the method @code{AggregateObject};
|
||||
@item The @code{Object} exports a method called @code{GetObject} that allows for discovery of other aggregated @code{Object}s.
|
||||
@item The @code{Object} is a kind of container that has the ability to aggregate other @code{Objects} using the method @code{AggregateObject};
|
||||
@item The @code{Object} exports a method called @code{GetObject} that allows for discovery of other aggregated @code{Objects}.
|
||||
@end itemize
|
||||
|
||||
@cindex base class
|
||||
@cindex Object
|
||||
It is crucially important to understand what we have described here
|
||||
(especially for those coming from other systems that provide similar
|
||||
functionality). A given C++ class has an object access interface that is
|
||||
@@ -1371,7 +1415,7 @@ which the class in question can inherit and be promoted to the status of
|
||||
ability to aggregate and search for other @code{Objects} that are added to
|
||||
its aggregation.
|
||||
|
||||
That last detail is important. In @command{ns-3} @code{Object}s are both
|
||||
That last detail is important. In @command{ns-3} @code{Objects} are both
|
||||
containers and specifications for a object method access. We have previously
|
||||
mentioned that the @code{Node} class acts as a container. In fact, the
|
||||
@code{Node} class inherits from @code{Object} and is itself an @command{ns-3}
|
||||
@@ -1382,10 +1426,11 @@ aggregation, the @code{Node} class also describes a public interface. THis
|
||||
public interface (API) is declared just as any C++ object is declared, via its
|
||||
class methods as specified in the inheritance tree. For those steeped in
|
||||
COM or CORBA, this is where the concept of Interface works in @command{ns-3}.
|
||||
Remember that it is generally true that @code{Object}s are both aggregations
|
||||
Remember that it is generally true that @code{Objects} are both aggregations
|
||||
and APIs.
|
||||
|
||||
@subsection Aggregations
|
||||
@cindex aggregate
|
||||
The figure below shows how an @code{Object} could be illustrated in detail.
|
||||
The line with the circle at the top of the diagram represents the appearance
|
||||
of the @code{Object} API to the external world. This circle and line are
|
||||
@@ -1393,8 +1438,9 @@ together called a lollipop because of its superficial similarity to a kind of
|
||||
childs candy.
|
||||
|
||||
@sp 1
|
||||
@center @image{oneif,,,,png}
|
||||
@center @image{oneobj,,,,png}
|
||||
|
||||
@cindex API
|
||||
You could declare this API and associated @code{Object} quite simply using a
|
||||
non-virtual class as follows,
|
||||
|
||||
@@ -1417,7 +1463,7 @@ non-virtual class as follows,
|
||||
};
|
||||
@end verbatim
|
||||
|
||||
The methods that are then available via the Interface labeled @code{A} in the
|
||||
The methods that are then available via the API labeled @code{A} in the
|
||||
figure above are the methods inherited from the @code{Object} base class
|
||||
(@code{GetObject}, @code{Ref}, and @code{Unref}) and those from class
|
||||
@code{A} (@code{MethodA}).
|
||||
@@ -1429,19 +1475,19 @@ identifies @code{Objects} at run-time as being instantiated from a particular
|
||||
class. We'll have much more to say about @code{TypiId} shortly.
|
||||
|
||||
You can think of the arc and arrow device coming off each side of the
|
||||
illustrated @code{Object}s as part of a connector. These connectors allow
|
||||
illustrated @code{Objects} as part of a connector. These connectors allow
|
||||
@code{GetObject} to search aggregations for an instance of a class type.
|
||||
The figure below shows an aggregation of three @code{Object}s: A, B and C.
|
||||
The figure below shows an aggregation of three @code{Objects}: A, B and C.
|
||||
The class declarations for classes @code{B} and @code{C} are substantially
|
||||
similar to that of class @code{A}.
|
||||
|
||||
@sp 1
|
||||
@center @image{threeif,,,,png}
|
||||
@center @image{threeobj,,,,png}
|
||||
|
||||
You can visualize these @code{Object}s as being snapped together like Lego
|
||||
building blocks if you like. When @code{Object}s are aggregated, a
|
||||
You can visualize these @code{Objects} as being snapped together like Lego
|
||||
building blocks if you like. When @code{Objects} are aggregated, a
|
||||
@code{GetObject} search path is formed through the connectors. In order
|
||||
to create this aggregation you will first need to create the Interface objects.
|
||||
to create this aggregation you will first need to create the @code{Objects}.
|
||||
These are just normal, everyday C++ objects that we can create using the
|
||||
@code{CreateObject} template function and manage using smart pointers. The
|
||||
following code should be obvious to you by now:
|
||||
@@ -1452,21 +1498,25 @@ following code should be obvious to you by now:
|
||||
Ptr<C> c = CreateObject<C> ();
|
||||
@end verbatim
|
||||
|
||||
When you create an aggregation, you pick one of the @code{Object}s of the
|
||||
@cindex aggregation
|
||||
When you create an aggregation, you pick one of the @code{Objects} of the
|
||||
aggregation to think of as the container. In this case well pick @code{Object}
|
||||
A. In order to aggregate an @code{Object}, you simply call the method
|
||||
@code{AggregateObject} that your class has inherited from class @code{Object}.
|
||||
The following code will aggregate @code{Object B} and @code{Object C} onto
|
||||
the @code{Object} (and container/aggregation) @code{A}.
|
||||
|
||||
@cindex AggregateObject
|
||||
@cindex GetObject
|
||||
@cindex Object
|
||||
@verbatim
|
||||
a->AggregateObject (b);
|
||||
a->AggregateObject (c);
|
||||
@end verbatim
|
||||
|
||||
Thats all there is to it. Now that you have those connectors snapped
|
||||
together, you can ask each of the @code{Object}s in the aggregation for any of
|
||||
the other @code{Object}s in the aggregation. Lets look at a simple example:
|
||||
together, you can ask each of the @code{Objects} in the aggregation for any of
|
||||
the other @code{Objects} in the aggregation. Lets look at a simple example:
|
||||
|
||||
@verbatim
|
||||
Ptr<B> newB = a->GetObject<B> ();
|
||||
@@ -1497,8 +1547,8 @@ This may be summarized by saying that @code{AggregateObject} takes an
|
||||
object instance of that type.
|
||||
|
||||
Now that you have those conceptual connectors snapped together, you can ask
|
||||
each of the @code{Object}s in the aggregation for any of the @code{Object}s
|
||||
in the aggregation. For example we could walk the @code{Object}s asking each
|
||||
each of the @code{Objects} in the aggregation for any of the @code{Objects}
|
||||
in the aggregation. For example we could walk the @code{Objects} asking each
|
||||
for the next in the aggregation. First we would ask the @code{Object} pointed
|
||||
to by the smart pointer @code{a} to look for the @code{Object} @code{class B}:
|
||||
|
||||
@@ -1513,6 +1563,7 @@ to look for the @code{Object} representing @code{class C}:
|
||||
Ptr<C> newC = newB->GetObject<C> ();
|
||||
@end verbatim
|
||||
|
||||
@cindex Object
|
||||
Then, we can ask the @code{Object} pointed to by the smart pointer @code{newC}
|
||||
to look for the @code{Object} representing @code{class A} and complete our
|
||||
circuit of the aggregation:
|
||||
@@ -1521,12 +1572,14 @@ circuit of the aggregation:
|
||||
Ptr<A> newA = newC->GetObject<A> ();
|
||||
@end verbatim
|
||||
|
||||
@cindex GetObject
|
||||
@code{GetObject} has some important properties that we need to go over.
|
||||
Technically, @code{GetObject} is a @emph{symmetric}, @emph{reflexive} and
|
||||
@emph{transitive} operation with respect to the set of aggregated
|
||||
@code{Object}s.
|
||||
@code{Objects}.
|
||||
|
||||
@subsubsection Symmetry
|
||||
@cindex symmetry
|
||||
The symmetric nature of @code{GetObject} guarantees that if one performs a
|
||||
@code{GetObject} on a given @code{Object} for the class of that same
|
||||
@code{Object}, that @code{GetObject} must succeed. In other words, the
|
||||
@@ -1549,6 +1602,7 @@ same @code{Object}. This call must always succeed and a smart pointer to the
|
||||
aggregated instance of that class is returned.
|
||||
|
||||
@subsubsection Reflexivity
|
||||
@cindex reflexivity
|
||||
Calls to @code{GetObject} must also be reflexive. This means that if you
|
||||
successfully @code{GetObject} for @code{Object B} from @code{Object A}, then
|
||||
you must always be able to @code{GetObject} for @code{A} from @code{B}. This
|
||||
@@ -1569,6 +1623,7 @@ succeeds, then a @code{GetObject} on @code{Object B} looking @code{Object A}
|
||||
must succeed.
|
||||
|
||||
@subsubsection Transitivity
|
||||
@cindex transitivity
|
||||
@code{GetObject} must also be transitive. This means that if one can
|
||||
find @code{Object B} from @code{Object A}, and @code{Object C} from
|
||||
@code{Object B}, then one must also be able to find @code{Object C} from
|
||||
@@ -1590,6 +1645,8 @@ If you can get to @code{Object B} from @code{Object A}, and you can get to
|
||||
@code{Object A} looking for @code{Object C} must also succeed.
|
||||
|
||||
@subsection Creating the TypeId
|
||||
@cindex TypeId
|
||||
@cindex GetTypeId
|
||||
The final piece of this puzzle is the @code{TypeId}. Recall that the
|
||||
declaration our eample object above included the following code
|
||||
|
||||
@@ -1634,6 +1691,7 @@ the boundaries should make sense to you.
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
@cindex function-local variable
|
||||
You are obviously looking at a global function associated with your class
|
||||
that simply returns a @code{TypeId}. Now, what about the rest. The code
|
||||
|
||||
@@ -1739,18 +1797,36 @@ use implementation inheritance to easily create new @code{Objects}. You are
|
||||
prevented from doing so in Microsoft COM, but this was almost universally
|
||||
identified as a problem.
|
||||
|
||||
So, looking at the entire @code{GetTypeId} declaration again,
|
||||
|
||||
@verbatim
|
||||
static ns3::TypeId GetTypeId (void)
|
||||
{
|
||||
static ns3::TypeId tid = ns3::TypeId ("A")
|
||||
.SetParent (Object::GetTypeId ())
|
||||
.AddConstructor<A> ();
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
it should be clear what is happening.
|
||||
|
||||
@subsection A Very Real Example
|
||||
@cindex Node
|
||||
@cindex AggregateObject
|
||||
@cindex GetObject
|
||||
@cindex Object
|
||||
At this point you may be asking yourself what the point of all of this is,
|
||||
since you already had those pointers laying around when you created the
|
||||
objects. The typical case is that one will create and aggregate some number
|
||||
of @code{Object}s in a constructor and return only a pointer to a single
|
||||
of @code{Objects} in a constructor and return only a pointer to a single
|
||||
@code{Object} as in our canonical example with @code{class Node}. In this
|
||||
case, the @code{Node} would be created and the @code{Node} constructor might
|
||||
create and call @code{AggregateObject} to aggregate the @code{Object}s for
|
||||
create and call @code{AggregateObject} to aggregate the @code{Objects} for
|
||||
internetwork routing and TCP/IP. From an external point of view, these
|
||||
aggregated objects may be discovered at run-time using @code{GetObject}.
|
||||
|
||||
Generally one tends to think of one of the @code{Object}s in the aggregation
|
||||
Generally one tends to think of one of the @code{Objects} in the aggregation
|
||||
as being the container and other @code{Objects} being aggregated to that
|
||||
container. In the case of a Node, for example, it is quite natural to think
|
||||
of the Node as being the container which contains protocol stacks, internet
|
||||
@@ -1782,6 +1858,9 @@ declaration for @code{InternetNode}.
|
||||
};
|
||||
@end verbatim
|
||||
|
||||
@cindex GetTypeId
|
||||
@cindex TypeId
|
||||
@cindex Object
|
||||
There is no declaration of a @code{static TypeId GetTypeId (void)} in this
|
||||
class. This means that the @code{InternetNode} is really not an @code{Object}
|
||||
for which you can @code{GetObject}. It turns out that the @code{InternetNode}
|
||||
@@ -1851,6 +1930,7 @@ system to create a unique @code{TypeId} for the @code{Ipv4} class and
|
||||
declares that @code{Ipv4} inherits from class @code{Object}. This is what
|
||||
makes an @code{Ipv4} an @code{Object}.
|
||||
|
||||
@cindex Ipv4
|
||||
It turns out that the Ipv4 class is an abstract base class (ABC). There are
|
||||
a number of pure virtual methods declared in that class. This means that
|
||||
an @code{Ipv4} object may not be instantiated. This is reflected by the fact
|
||||
@@ -1863,6 +1943,7 @@ required virtual methods. This is where understanding what is an
|
||||
that you see @code{GetTypeId} there tells you that the @code{Ipv4} class is
|
||||
the class for which you can @code{GetObject}.
|
||||
|
||||
@cindex implementation class
|
||||
The class @code{Ipv4Impl} provides an implementation for the pure virtual
|
||||
methods in @code{Ipv4}. Since class @code{Ipv4} cannot be instantiated, one
|
||||
instantiates the @code{Ipv4Impl} class to create an @code{Ipv4} @code{Object}.
|
||||
@@ -1897,6 +1978,7 @@ This is exactly the same thing that is happening in the case of the
|
||||
Ptr<Node> n = CreateObject<InternetNode> ();
|
||||
@end verbatim
|
||||
|
||||
@cindex implementation object
|
||||
@code{CreateObject} is being called to create an implementation object,
|
||||
in this case @code{InternetNode}, which implements the methods of the
|
||||
@code{Node Object}. It is the resulting @code{Node Object} which you would
|
||||
@@ -1915,16 +1997,19 @@ Rather you should understand that the @emph{proper} @code{Object} is the
|
||||
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
|
||||
@end verbatim
|
||||
|
||||
@cindex CreateObject
|
||||
This does illustrate that the fact that whether an object created by
|
||||
@code{CreateObject} is or is not an @code{Object} in the usual sense can be
|
||||
quite well hidden if you are casually looking at the object creation code.
|
||||
The designers of the system had long and involved discussions on this issue
|
||||
and in the end decided that mnemonic aids such as Hungarian notation were a
|
||||
stylistic thing and you should just refer to the system documentation to
|
||||
determine what objects are @command{ns-3} @code{Object}s and what the APIs
|
||||
of those @code{Object}s actually are (RTFM --- as in Read the Fine Manual,
|
||||
determine what objects are @command{ns-3} @code{Objects} and what the APIs
|
||||
of those @code{Objects} actually are (RTFM --- as in Read the Fine Manual,
|
||||
of course).
|
||||
|
||||
@cindex AggregateObject
|
||||
@cindex Object
|
||||
In the case of @code{Ipv4Impl}, you know that the class inherits somehow
|
||||
from @code{Object} since there is a call to @code{AggregateObject} that
|
||||
refers to an instance of an @code{Ipv4Impl}. You will have to go to
|
||||
@@ -1946,6 +2031,10 @@ code in this file:
|
||||
ipv4->SetDefaultRoute (Ipv4Address (``10.1.1.2''), 1);
|
||||
@end verbatim
|
||||
|
||||
@cindex InternetNode
|
||||
@cindex Node
|
||||
@cindex Object
|
||||
@cindex GetObject
|
||||
The first line creates an @code{InternetNode} implementation object and casts
|
||||
the resulting smart pointer to a @code{Node} as we have discussed extensively.
|
||||
The next line shown declares a smart pointer to an @code{Ipv4 Object}. We
|
||||
@@ -1962,13 +2051,18 @@ There are a few things that you should remember but which may not be
|
||||
immediately obvious.
|
||||
|
||||
@subsection Ns-3 Objects are Associated with Classes not C++ objects
|
||||
@cindex Object
|
||||
@cindex GetObject
|
||||
@cindex iterate
|
||||
@cindex aggregation
|
||||
@cindex GetNDevices
|
||||
Okay, you can see some of the problems with the terminology popping up again.
|
||||
We are reminding you that when you do a GetObject you are providing the key
|
||||
to the lookup by giving a class name and not anything that is unique to a
|
||||
C++ object.
|
||||
|
||||
You cannot add more than one @code{Object} of a given type (class name) to an
|
||||
aggregation. If you need to contain a number of @code{Object}s of the same
|
||||
aggregation. If you need to contain a number of @code{Objects} of the same
|
||||
type in the same aggregation, you will need to provide a separate container
|
||||
over which you can iterate. For example, the @code{Node} class provides
|
||||
methods,
|
||||
@@ -1978,12 +2072,13 @@ methods,
|
||||
Ptr<NetDevice> GetDevice (uint32_t index) const;
|
||||
@end verbatim
|
||||
|
||||
that are used iterate over the multiple @code{NetDevice} @code{Object}s
|
||||
that are used iterate over the multiple @code{NetDevice} @code{Objects}
|
||||
associated with it.
|
||||
|
||||
@emph{Remember: Object types do not identify objects.}
|
||||
|
||||
@subsection Dont use QI to Check Your Own Type.
|
||||
@subsection Dont use GetObject to Check Your Own Type.
|
||||
@cindex GetObject
|
||||
It is tempting to use @code{GetObject} as a form of runtime type
|
||||
information. Dont do it. You have no control over what @emph{other}
|
||||
object may be added to your aggregation. Someone else may have
|
||||
@@ -2015,20 +2110,25 @@ interface. If this failed, it could then infer that it had a TCP
|
||||
implementation and would then do any TCP-specific tasks it could.
|
||||
|
||||
Now, what happens when these two working objects are aggregated together by
|
||||
some innocent end-user. Since the @code{Object}s are conceptually snapped
|
||||
some innocent end-user. Since the @code{Objects} are conceptually snapped
|
||||
together, the TCP implementation would suddenly begin finding the UDP
|
||||
Interface from the other class factory and think it was the UPD implementation.
|
||||
|
||||
@emph{Objects should not be used as run-time type information.}
|
||||
|
||||
@section Connecting the Dots
|
||||
@cindex Object
|
||||
@cindex GetObject
|
||||
@cindex AggregateObject
|
||||
@cindex GetTypeId
|
||||
@cindex API
|
||||
This may all sound very complicated to you if this is your first exposure to
|
||||
these concepts. It may be annoying if I tell you that its really not as hard
|
||||
as it sounds. Rest assured that if you take some time, look at and understand
|
||||
the examples and write a little test code it will all come together for you.
|
||||
Grep around the system for @code{AggregateObject} and @code{GetObject} and
|
||||
take a look at how we have used them. This will also give you a good idea of
|
||||
what our core @code{Object}s and associated APIs are. If you grep for
|
||||
what our core @code{Objects} and associated APIs are. If you grep for
|
||||
@code{GetTypeId} you will find most, if not all of the @code{Object} API
|
||||
interface declarations in the system. The more you see this idiom in
|
||||
use, the more comfortable you will be with the idea and the more you will see
|
||||
@@ -2055,8 +2155,9 @@ form of extra confusion or extra complexity somewhere in the system. The
|
||||
resulting system is extremely flexible and easy to use. It is, unfortunately,
|
||||
sometimes hard to document and talk about.
|
||||
|
||||
@cindex Feynman
|
||||
If it helps you to think in terms of Microsoft COM and Interfaces, by all means
|
||||
do so, just be aware that even though @command{ns-3} @code{Object}s descend
|
||||
do so, just be aware that even though @command{ns-3} @code{Objects} descend
|
||||
from COM in some sense, there are subtle differences that may get you lost or
|
||||
into trouble. So to paraphrase Feynman one more time,
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
BIN
doc/tutorial/threeobj.png
Normal file
BIN
doc/tutorial/threeobj.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Reference in New Issue
Block a user