A question about downcast netdevice pointer.

914 views
Skip to first unread message

kido

unread,
Sep 24, 2008, 9:09:04 PM9/24/08
to ns-3-users
Hi,

I am new user of ns3. When I try to downcast the netdevice pointer, I
got error message.

I use the example file of realtime-udp-echo.cc What I did is what to
get the one of CsmaNetDevice pointers.

Ptr<Node> node = n.Get(2);
Ptr<NetDevice> dev = node->GetDevice(0);
if (dynamic_cast<CsmaNetDevice*>(PeekPointer (dev))){
.................
}

When I compile the program, I received the compile error for the
dynamic_cast as:

../scratch/emulator.cc:149: error: cannot dynamic_cast
'ns3::PeekPointer [with T = ns3::NetDevice](((const
ns3::Ptr<ns3::NetDevice>&)((const ns3::Ptr<ns3::NetDevice>*)(&
dev))))' (of type 'class ns3::NetDevice*') to type 'struct
ns3::CsmaNetDevice*' (target is not pointer or reference to complete
type)

How should I do this downcast? I borrow the code from
csma-net-device.cc. I don't understand why the code in that file is no
problem.

Regards

kido

unread,
Sep 24, 2008, 10:01:57 PM9/24/08
to ns-3-users
I think I figured it out the reason.

I missed the header file of

include "ns3/csma-module.h"

Tom Henderson

unread,
Sep 25, 2008, 1:05:45 AM9/25/08
to ns-3-...@googlegroups.com

Another way you can do this downcast (although in looking at our
documentation tonight, it is not very well documented in either the
tutorial or manual) is to use the GetObject method:

Ptr<Node> node = n.Get(2);
Ptr<NetDevice> dev = node->GetDevice(0);

Ptr<CsmaNetDevice> csmaDev = dev->GetObject<CsmaNetDevice> ();

This queries the NetDevice object to see if it has a CsmaNetDevice
interface aggregated to it. But if you have the dynamic_cast method
working, it should be more or less equivalent.

Tom

Nan Li

unread,
Sep 25, 2008, 12:05:28 PM9/25/08
to ns-3-...@googlegroups.com
Thanks your answer.
I just have a little confuse about this.

dynamic_cast is a straight thought about converting base
class(netdevice) pointer to child class (csmanetdevice) pointer, which
means there is only one object.

"aggregated" seems there are two objects aggregated together. Why
there is CsmaNetDevice object aggregated with a NetDevice object?

I went throught the code, it seems there is only one object
(CsmaNetDevice) for each node.

Am I right?

Thanks,

--
Thanks,
Nan Li

Gustavo Carneiro

unread,
Sep 25, 2008, 12:16:22 PM9/25/08
to ns-3-...@googlegroups.com, ns-developers


2008/9/25 Nan Li <kid...@gmail.com>


Thanks your answer.
I just have a little confuse about this.

dynamic_cast is a straight thought about converting base
class(netdevice) pointer to child class (csmanetdevice) pointer, which
means there is only one object.

"aggregated" seems there are two objects aggregated together. Why
there is CsmaNetDevice object aggregated with a NetDevice object?

I went throught the code, it seems there is only one object
(CsmaNetDevice) for each node.

Am I right?

You are right, there is only one object.

I for one find using GetObject<SubClass>() for downcasts less intuitive than dynamic_cast, but I am aware some other developers don't quite agree with me for whatever reason.

Although dynamic_cast<CsmaNetDevice*> (PeekPointer (dev)) is a bit more verbose.  Ideally I think it would make a lot of sense to have a smart-pointer based dynamic cast variant, something like:

static inline Ptr<T2> DynamicCast<T2> (Ptr<T1> ptr)
{
   return Ptr<T2> (dynamic_cast<T2*> (PeekPointer (ptr)));
}

Unfortunately the idea got no traction, at the time.

 



--
Gustavo J. A. M. Carneiro
INESC Porto, Telecommunications and Multimedia Unit
"The universe is always one step beyond logic." -- Frank Herbert

Mathieu Lacage

unread,
Sep 25, 2008, 12:19:24 PM9/25/08
to ns-3-...@googlegroups.com

On Thu, 2008-09-25 at 12:05 -0400, Nan Li wrote:
> Thanks your answer.
> I just have a little confuse about this.
>
> dynamic_cast is a straight thought about converting base
> class(netdevice) pointer to child class (csmanetdevice) pointer, which
> means there is only one object.
>
> "aggregated" seems there are two objects aggregated together. Why
> there is CsmaNetDevice object aggregated with a NetDevice object?

It just happens that the Object::GetObject method defined in
src/core/object.h also does a dynamic_cast as part of the aggregation
lookup so, if you use GetObject, you get a dynamic cast for free. The
syntax is slightly more readable than a raw dynamic_cast in my opinion.

> I went throught the code, it seems there is only one object
> (CsmaNetDevice) for each node.

No, you could 'add' multiple CsmaNetDevice to a single node and that is
how multi-interface support is implemented in ns-3. 'Aggregation' is a
different concept which is supported by the Object::AggregateObject
method.

regards,
Mathieu

Mathieu Lacage

unread,
Sep 25, 2008, 12:21:37 PM9/25/08
to ns-3-...@googlegroups.com, ns-developers

On Thu, 2008-09-25 at 17:16 +0100, Gustavo Carneiro wrote:

>
> Although dynamic_cast<CsmaNetDevice*> (PeekPointer (dev)) is a bit
> more verbose. Ideally I think it would make a lot of sense to have a
> smart-pointer based dynamic cast variant, something like:
>
> static inline Ptr<T2> DynamicCast<T2> (Ptr<T1> ptr)
> {
> return Ptr<T2> (dynamic_cast<T2*> (PeekPointer (ptr)));
> }
>
> Unfortunately the idea got no traction, at the time.

I (maintainer hat on) would be fine with a patch to define a dynamic
cast template function in src/core/ptr.h

Mathieu

Tom Henderson

unread,
Sep 25, 2008, 1:04:10 PM9/25/08
to ns-3-...@googlegroups.com, ns-developers

>-----Original Message-----
>From: Gustavo Carneiro [mailto:gjcar...@gmail.com]
>Sent: Thursday, September 25, 2008 08:16 AM
>To: ns-3-...@googlegroups.com
>Cc: 'ns-developers'
>Subject: Re: A question about downcast netdevice pointer.
>
>2008/9/25 Nan Li <kid...@gmail.com>

>
>>
>> Thanks your answer.
>> I just have a little confuse about this.
>>
>> dynamic_cast is a straight thought about converting base
>> class(netdevice) pointer to child class (csmanetdevice) pointer, which
>> means there is only one object.
>>
>> "aggregated" seems there are two objects aggregated together. Why
>> there is CsmaNetDevice object aggregated with a NetDevice object?
>>
>> I went throught the code, it seems there is only one object
>> (CsmaNetDevice) for each node.
>>
>> Am I right?
>
>
>You are right, there is only one object.
>
>I for one find using GetObject<SubClass>() for downcasts less intuitive than
>dynamic_cast, but I am aware some other developers don't quite agree with me
>for whatever reason.

Gustavo, yes, we discussed this before (in the context of Queue objects, IIRC).

The question was, whether GetObject<> () was the preferred approach for downcasting in ns-3, or whether dynamic_cast was preferred.

I think we agreed at the time that GetObject<> () was more suitable for finding out whether an object has an optional component aggregated to it (e.g., is there an EnergyModel that must be decremented when a wireless device makes a transmission?) but that pure downcasting was more straightforward to do dynamic_cast (although GetObject<> () does work in many cases), although the syntax could be improved as you suggest.

>
>Although dynamic_cast<CsmaNetDevice*> (PeekPointer (dev)) is a bit more
>verbose. Ideally I think it would make a lot of sense to have a
>smart-pointer based dynamic cast variant, something like:
>
>static inline Ptr<T2> DynamicCast<T2> (Ptr<T1> ptr)
>{
> return Ptr<T2> (dynamic_cast<T2*> (PeekPointer (ptr)));
>}
>
>Unfortunately the idea got no traction, at the time.

In my reply, I was simply pointing out the other workable way but not prescribing it. If this is considered ns-3 best practice (e.g., users SHOULD dynamic_cast but MAY GetObject), I will try to document it somewhere, and maybe we accept the above patch once tested?

Tom

cra...@gmail.com

unread,
Sep 25, 2008, 3:14:52 PM9/25/08
to ns-3-...@googlegroups.com

> > "aggregated" seems there are two objects aggregated together. Why
> > there is CsmaNetDevice object aggregated with a NetDevice object?
> >
> > I went throught the code, it seems there is only one object
> > (CsmaNetDevice) for each node.
> >
> > Am I right?
>
> You are right, there is only one object.
>
> I for one find using GetObject<SubClass>() for downcasts less
> intuitive than
> dynamic_cast, but I am aware some other developers don't
> quite agree with me
> for whatever reason.

A little history may help to understand what is happening here.

By design there are two distinct ways one can look at this whole object
aggregation idea. We went through a long series of arguments regarding
whether or not to allow object-like behavior or to call these things
Interfaces and only allow COM-like behavior. The end result is a unique
system that you can view as a complexified object system or a simplified COM
system. What you're running into now is the blurry line where those two
models meet.

When I wrote the initial documentation on this, I was fond of quoting
Richard Feynman's (American physicist) comments about wave-particle duality.
What we have here is an interface-object duality; and different people look
at it in different ways at different times, just like physicists view
photons, for example.

If you look at the CsmaNetDevice as a collection of Interfaces, you'll see
that there is an Object Interface, a NetDevice Interface, and a
CsmaNetDevice Interface involved. If you don't concern yourself with how
these interfaces are implemented, the COM-like Interface model makes perfect
sense. In that case, you wouldn't ever consider doing a dynamic cast to get
from one Interface to another since they may be implemented in completely
different ways. You would do an interface query. If you neglect the
implementation and accept for a moment that QueryInterface is spelled
GetObject in our system, the GetObject makes good sense:

Ptr<CsmaNetDevice> nd = dev->GetObject<CsmaNetDevice> ();

In this conceptual model, you have a pointer to an Interface in an
aggregation, and you're doing a QueryInterface equivalent on the aggregation
looking for the CsmaNetDevice Interface. It doesn't matter how that
aggregation is implemented at all. I personally look at things this way,
and it makes perfect sense for me to move around in the object hierarchy
just like this. I don't have to care about how the underlying object author
decided to implement the Interfaces. If someone aggregates another Object
to the CsmaNetDevice, I get to it in the same way and I don't have to care
about how that new object was implemented (through inheritance or
aggregation).

Now, if you are looking at the situation from the perspective of the
implementer of the CsmaNetDevice, the picture changes. In this case, you
know you have implemented the CsmaNetDevice as an object that inherits from
NetDevice which, in turn, inherits from Object. If you look at the world
this way, you'll tend to think of doing a downcast to move from a NetDevice
Ptr to a CsmaNetDevice Ptr. In this case, Gustavo's DynamicCast makes good
sense:

Ptr<CsmaNetDevice> nd = DynamicCast<CsmaNetDevice> (dev);

In this particular case, the two approaches accomplish the same thing and we
have previously decided that developers can choose to look at the situation
in whatever way they want.

Regarding that choice, we went around and around about whether or not to
enforce one view or another on our users and we ended up deciding that it
was all a matter of taste which world-view you found more appealing. We
considered a more dictatorial approach in which all Interfaces (in the COM
sense) were broken out and it was made excruciatingly obvious what things
were public Interfaces and how they were implemented. In that case, it
would've been obvious that when you put together a CsmaNetDevice you would
have a CsmaNetDevice Interface that inherited from Object, and a NetDevice
Interface that also inherited from Object; and these two Interfaces would've
been explicitly aggregated even though they may have been implemented via
inheritance. The trade-off was explicit construction, and ease of
documentation and understanding, versus having to write all of the code in
all of the files to implement all of this. In the explicit approach you
would have had pure virtual Interface declaration headers with corresponding
implementations that were explicitly aggregated together.

Another approach was to make much of this implicit; and allow us to build
devices in the normal C++ way. We made existing class hierarchies work in
the object aggregation setting. You could build a CsmaNetDevice object that
inherited from NetDevice and Object, and present them to the world as an
aggregation of those three Interfaces without having to write all of the
interface code. You could also treat this class hierarchy as you would in a
normal C++ situation. This made backfitting the Object system into an
existing ns-3 easy and resulted in less required code to implement
interfaces (there were other plusses and minuses talked about as well, even
down to how source files were displayed on your screen when you typed 'ls').


As has been observed, there can be confusion since this is done implicitly.
Even more confusion can happen when you introduce implementation classes --
classes that implement Interfaces/Objects but that have no type and aren't
really first-class Objects with Interfaces but are accessible by dynamic
cast. The main problem in using this Object-as-Interface approach, as has
been recently rediscovered, is that there is no easy way to figure out which
"Interfaces" are exported -- you get to read the source code and know how
the object model works.

The problem is exacerbated by naming. We decided that pure virtual
Interfaces in the COM sense aren't what we deal with -- we are talking about
Objects which are really C++ objects. We originally used QueryInterface as
the name for the interface discovery mechanism. We changed to QueryObject
when we changed the emphasis to Object from Interface. After much
"discussion" we decided it was important to convey that we were getting a
pointer to an underlying C++ object, not some other special kind of thing.
The name ended up being GetObject. Of course, when we did this, we lost the
association with COM that kindof held the whole model together conceptually.

We voted for flexibility over understandability in an explicit choice in
this case.

We were going to address the confusion by documentation, but that seems to
have fallen by the wayside. You can find a slightly out-of-date version of
my attempt to convey all of this in ns-3-dev/doc/manual/other.texi
(understand that it *is* out-of-date). Look for the "Object Model" section.

-- Craig

zahed052

unread,
Nov 21, 2017, 11:07:27 AM11/21/17
to ns-3-users
Hi Craigdo,

I am trying to call a function implemented in a sub class mac layer using a pointer to the base mac layer. I tried both DynamicCast and GetObject methods. However, every time  mac addresses of all of my nodes becomes 00:00:00:00:00:00

If I put that function in the base layer it works, but this function is only specific to sub class. Any help would be appreciated.

Thanks,

Tommaso Pecorella

unread,
Nov 21, 2017, 7:40:42 PM11/21/17
to ns-3-users
Hi,

please read the posting guidelines, open a new thread and give us some examples of the non-working code.
In that order.

T.
Reply all
Reply to author
Forward
0 new messages