NS3 Object模型内容翻译

ns-3-manual.pdf 对象模型翻译

1.6 对象模型 Object model

ns-3 本质上是一个基于 C++对象的系统。对象可以像往常一样依照 C++的规则
被声明以及实例化。ns-3 还给传统的 C++对象添加了一些新的特色来提供更强
的功能。本章为读者介绍 ns-3 的对象模型。

本节描述针对 ns-3 的对象的 C++类设计。总的来说,已经使用的设计模式包括
经典的 object-oriented 设计(多态的接口和实现)、接口与实现相分离、非虚
拟的公共接口设计模式、对象聚合设施以及 reference counting for memory
management。尽管 ns-3 的设计与上述的任意一个都不严格一致,但熟悉类似
COM 或 Bonobo 等构件模型的人将能够识别 ns-3 对象聚合模型中的设计元素。

1.6.1 面向对象行为 Object-oriented behavior

一般而言,C++对象提供常见的面向对象功能(抽象、封装、继承以及多态),
这些功能是经典的面相对象设计的一部分。ns-3 对象使用了这些特性。例如:

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;
...
};

1.6.2 对象的基类 Object base classes

ns-3 中有 3 个特殊的基类。由 3 个基类继承的类能够用特殊的特性来实例化对
象。这 3 个基类是:

class Object
class ObjectBase
class RefCountBase

没有要求 ns-3 的对象都继承自这 3 个类,
但对于具有特殊特性的类,是这样的。

由 class Object 派生的类具有如下特性。

    ns-3 的类型和属性系统(参看 Attributes)。
    对象聚合系统
    a smart-pointer reference counting system (class Ptr)

由 class ObjectBase 派生的类具有上述前两个特性,不具有 smart pointers。

由class RefCountBase 派生的类只具有 the smart-pointer reference counting system.

在实际中,ns-3 的开发者碰到最多的是上述 3 个中的 class Object。

1.6.3 内存管理和类 Ptr Memory management and class Ptr

C++程序中的内存管理是一个复杂的过程,并且经常被不正确地处理或者被不一
致地处理。以下介绍我们决定使用的一个引用计数设计。

所有使用引用计数的对象都维护一个内部引用值,根据该值来决定对象什么时候
可以安全地删除他自身。每当有接口获得对象的指针时,该对象的引用计数值就
增加 1,这个增加是通过调用 calling Ref() 完成的。当用户不再使用该指针时,
该指针的用户负责显式调用 Unref() 来解除对该指针的引用。当引用计数减到 0
时,对象被删除。

• 当用户代码通过创建对象从该对象获得指针或者通过 QueryInterface 获得指针时,没有必要增加引用计数值。
• 当用户代码从其他的源(比如,对指针进行复制)获得指针时,用户代码必须调用 Ref() 来增加引用计数值。
• 该对象的指针的所有用户都必须调用 Unref() 来释放引用。

通过使用下边描述的 reference counting smart pointer class,调用 Unref() 的
负担有了一些缓解。

通过底层 API,并想在堆上显式分配 non-reference-counted 对象的用户使用
new 操作符,用户负责删除这类对象。

Reference counting smart pointer (Ptr)

引用计数智能指针(Ptr)Reference counting smart pointer (Ptr)
因为始终调用 Ref() 和 Unref() 很麻烦,所以 ns-3 提供类似于
Boost::intrusive_ptr 的智能指针 class Ptr。该智能指针类假定底层类型提供一

对 Ref 和 Unref 方法,且该对方法增加和减少对象的内部引用计数值。
这种实现使得你能够像操纵普通指针一样操纵智能指针:可以将他和 0 比较、
将他和其他指针比较以及给他赋 0 值,等等。

通过 GetPointer 和 PeekPointer 方法有可能从智能指针中提取出裸指针。
如果你想把用 new 产生的对象存储到一个智能指针。为了避免内存泄漏,我们
建议你使用 CreateObject 模板函数来创建对象并将他存储到智能指针。这些函
数是很小的便利函数,他们的目标仅仅是使你少敲些键盘。

1.6.4 CreateObject 和 Create CreateObject and Create

C++的对象可以被静态地创建、动态地创建以及自动地创建。这在 ns-3 中同样
适用,但系统中的一些对象有一些附加的框架。特别地,引用计数的对象通常使
用模板化的 Create 或 CreateObject 方法被分配。

对于由 class Object 派生的对象:

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

不要使用 operator new 来创建这类对象。应该使用 CreateObject() 来创建。

对于由 class RefCountBase 派生的对象,或其他支持智能指针类用法的对象
(特别地,比如 ns-3 Packet class),建议使用模板化的 helper function:

Ptr<B> b = Create<B> ();

这是一个对 new 操作符的封装,他正确地处理了引用计数系统。

1.6.5 聚合 Aggregation

ns-3 的对象聚合系统很大程度上是由一个认识促成的,即 ns-2 中一个很普遍
的用法是通过继承和多态来扩展协议模型。例如,TCP 的特殊版本
RenoTcpAgent 是由类 TcpAgent 派生的,并对基类的函数进行覆盖(override)。
尽管如此,ns-2 模型中出现的两个问题是 downcasts 和“weak base class” 。

Downcasting 是指一个过程,即使用指向某个基类对象的指针并在程序运行时查
询该指针来获得类型信息,然后将该指针显式转换为子类的指针,以便子类的
API 能够使用。

Weak base class 是指当某个类无法被有效地重用(由他进行派
生)出现的问题,因为他缺少必要的功能,导致开发者不得不修改基类,这将导
致基类 API 的增生,某些 API 可能并不是对所有子类都在语义上正确。

ns-3 使用查询接口设计模式来避免这些问题。该设计基于 Component Object
Model 和 GNOME Bonobo 的基础。尽管现在替代构件的完全的二进制兼容性
还不被支持,但我们努力简化语法和对模型编写者的影响。

1.6.6 聚合的例子 Aggregation example

ns-3 中,class Node 是使用聚合的一个很好的例子。注意 ns-3 中没有类 Node
的派生类(比如类 InternetNode 等),而是将构件(各种协议)聚合到节点中。
我们来研究一些 Ipv4 协议是如何被加入节点的。

static void
AddIpv4Stack(Ptr<Node> node)
{
Ptr<Ipv4L3Protocol> ipv4 = CreateObject<Ipv4L3Protocol> ();
ipv4->SetNode (node);
node->AggregateObject (ipv4);
Ptr<Ipv4Impl> ipv4Impl = CreateObject<Ipv4Impl> ();
ipv4Impl->SetIpv4 (ipv4);
node->AggregateObject (ipv4Impl);
}

注意 Ipv4 协议是用 CreateObject() 创建的。接着 Ipv4 协议被聚合到节点中。
这样,基类 Node 就不需要被编辑来使得用户使用指向基类 Node 的指针来访问
Ipv4 接口;用户可以在程序运行时来向节点请求指向该节点的 Ipv4 接口的指针。
用户如何向节点提出请求在下一小节描述。

注意:将多于一个的同一类型的对象聚合到某个 ns3::object 是编程错误。所以,
如果想要存储一个节点的所有活动的 sockets,聚合是不可选的。

GetObject 的例子 GetObject example

GetObject 是一个获得安全 downcasting 的类型安全的方法,并且使得接口能够
在对象上被找到。

考虑一个节点的指针 m_node,该指针指向一个节点对象,且先前已经将 Ipv4
的实现聚合到了该节点。客户代码想要配置一个默认的路由。为了实现这点,必
须访问该节点内的一个对象,且该对象具有 IP 转发配置的接口。如下:

Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();

如果实际上没有 Ipv4 的对象被聚合到该节点,那么该方法将返回 null。因此,
检查该函数调用的返回值是一个好习惯。如果成功,则用户可以使用 Ptr,该指
针指向先前被聚合到该节点的 Ipv4 对象。

另一个如何使用聚合的例子是给对象添加可选的模型。例如,一个现存的 Node
对象可以具有一个在运行时被聚合到该节点对象的“Energy Model”对象(不需要
对节点类进行修改和重新编译)。一个现存的模型(比如一个无线网络设备)可
以通过”GetObject”来获得该能量模型并表现地就像该接口是内建在 Node 对象
的底层或者该接口是在运行时被聚合到该节点的。而其他节点却不需要知道能量
模型的任何事情。
我们希望这样的编程模式可以大量减小开发者修改各种基类的必要。

1.6.7 Object factories

一个常见的用法例子是创建许多相似的配置对象。你可以重复调用CreateObject(),
但是在ns-3中也有一个工厂设计模式。它已经在“helper” API中已经大量使用了。
ObjectFactory类可以用来初始化对象,和配置这些对向的属性:

void SetTypeId (TypeId tid);
void Set (std::string name, const AttributeValue &value);
Ptr<T> Create (void) const;

第一个方法允许你使用ns-3 TypedId系统来具体指定创建对象的类型。
第二个方法允许你设置要创建对象的属性。
第三个方法允许你使用工厂对象自己创建对象。

例如:

ObjectFactory factory;
// Make this factory create objects of type FriisPropagationLossModel
factory.SetTypeId ("ns3::FriisPropagationLossModel")
// Make this factory object change a default value of an attribute, for
// subsequently created objects
factory.Set ("SystemLoss", DoubleValue (2.0));
// Create one such object
Ptr<Object> object = factory.Create ();
factory.Set ("SystemLoss", DoubleValue (3.0));
// Create another object with a different SystemLoss 再次创建一个对戏那个
Ptr<Object> object = factory.Create ();

1.6.8 Downcasting

有一个经常出现的问题:”假设我有一个基类的指针(Ptr),该指针指向一个对
象,如果我想要派生类的指针,那么我应该进行 downcast(通过 C++的动态类
型转换)来获得派生的指针还是应该使用对象聚合系统进行 GetObject<> () 来
找到一个 Ptr,该指针指向子类 API 的接口”?

这个问题的答案是:在多数情况下,两种技术都行的通。ns-3 提供一个模板化
的函数,该函数使得对象动态类型转换的语法更加友好:

template <typename T1, typename T2>
Ptr<T1>
DynamicCast (Ptr<T2> const&p)
{
return Ptr<T1> (dynamic_cast<T1 *> (PeekPointer (p)));
}

当程序员有一个基类的指针,想和一个子类的指针进行测试时,DynamicCast
行的通。当寻找被聚合的不同对象时, GetObject 行的通。但对于子类, GetObject
也行的通,和 DynamicCast 一样。如果不确定,那么程序员应该使用 GetObject,
因为他在所有情况下都适用。如果程序员知道所考虑的对象的类层次结构,使用
DynamicCast 更加直接。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • 以下是ns3手册内容翻译 在 ns-3 的模拟中,主要有两个方面的设置: 模拟拓扑和对象是如何连接的。 在拓扑中实...
    shawn168阅读 3,441评论 0 1
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,446评论 1 51
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,635评论 0 9
  • 重新系统学习下C++;但是还是少了好多知识点;socket;unix;stl;boost等; C++ 教程 | 菜...
    kakukeme阅读 19,422评论 0 50
  • 作者 范友军 遥远 总想扯一片详云 把怀念的思绪一起融合 怀揣一杯红酒 站在离乡的这头 村口 善良的母亲总爱在翘盼...
    中原焦点阅读 214评论 2 3