C++ - 邂逅对象

C的++

本文为那些年我们追过的语言之C++篇。C语言的命名来源于其参考的B语言. 而C++的命名, 正因为所有C的思想和规律基本都被保留下来, 并且引入了类的概念, 以及封装, 继承, 多态的思想. 关键是观念的转变. 系统学习, 推荐 C++ Primer .

黑魔法

1. 模板 (Template)

虽然类是C++与C最直观的区分方式, 但本文并不打算在其耗费笔墨. 相较类, 多态的特性更吸引我. 模板是一种对类型进行参数化的工具, 通常有两种形式: 针对参数类型不同的函数模板, 以及针对属性和操作类型不同的类模板. 使用模板可以为类或函数声明构造一种通用模式, 使类中某些成员或者函数的参数及返回值类型任意。深入学习请阅读 C++ Templates .

2. 标准模板库 (STL)

STL (Standard Template Library) 的核心部件包括: 容器 (Container), 算法 (Algorithms), 迭代器 (Iterator). 简单来说, 它们各自表示结构, 操作, 指针. STL的一个重要特性是它不是面向对象的. 它基于模板而不是OOP中的封装, 继承, 多态. 关于STL的内容请参考学习:

在C++ STL中, 很多部分 (set, multiset, map, multimap) 应用了红黑树的变体. 红黑树操作具有良好的最坏情况复杂度, 在实践中, 它可以进行O(log n)时间内的查找,插入和删除等操作. 红黑树是每个节点都带有红色或黑色的二叉平衡查找树. 具有如下性质:

  1. 节点是红色或黑色.
  2. 根节点是黑色.
  3. 每个叶节点 (NIL节点) 是黑色.
  4. 每个红色节点的两个子节点都是黑色, 从每个叶子到根的所有路径上不能有两个连续的红色节点.
  5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点.

这些性质确定了红黑树的关键性质: 从根到叶子的最长可能路径不多于最短可能路径的两倍长. 其好处是既保持了树的相对平衡, 又比AVL的插入删除操作的复杂性低许多. 红黑树的插入及删除操作会破坏性质, 因此需要通过旋转来维护. 直观了解维护操作请看红黑树从头至尾插入和删除结点的全程演示图. 该文作者所写的红黑树专题非常翔实, 值得研读.

3. 回调 (Callback)

更准确的说, 回调是C的性质. 首次接触回调函数是在ns-3中, 其作用是让某函数以函数指针的形式成为某个类的属性, 以供该类在适当的时候调用该函数. 引用ns-3的Tutorial中的讲解:

The goal of the Callback system in ns-3 is to allow one piece of code to call a function (or method in C++) without any specific inter-module dependency. This ultimately means you need some kind of indirection – you treat the address of the called function as a variable. This variable is called a pointer-to-function variable.

举个ns-3中遇到的关于wifi中mac层收包的例子, 为保证原汁原味, 代码中部分与回调无关的内容并未删去:

class MacRxMiddle{
  typedef Callback<void, Ptr<Packet>, const WifiMacHeader*> ForwardUpCallback;
  ForwardUpCallback m_callback;
  void SetForwardCallback (ForwardUpCallback callback);
  void Receive (Ptr<Packet> packet, const WifiMacHeader *hdr);
  ...
};

void MacRxMiddle::SetForwardCallback (ForwardUpCallback callback){
  m_callback = callback;
}

void MacRxMiddle::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr){
  NS_LOG_FUNCTION (packet << hdr);
  NS_ASSERT (hdr->IsData () || hdr->IsMgt ());
  OriginatorRxStatus *originator = Lookup (hdr);
  if (!(SequenceNumber16 (originator->GetLastSequenceControl ()) < SequenceNumber16 (hdr->GetSequenceControl ()))) NS_LOG_DEBUG ("Sequence numbers have looped back. last recorded=" << originator->GetLastSequenceControl () << " currently seen=" << hdr->GetSequenceControl ());
  if(IsDuplicate (hdr, originator))
    NS_LOG_DEBUG ("duplicate from=" << hdr->GetAddr2 () <<", seq=" << hdr->GetSequenceNumber () <<", frag=" << hdr->GetFragmentNumber ());
    return;
  }
  Ptr<Packet> agregate = HandleFragments (packet, hdr, originator);
  if (agregate == 0) return 0;
  if (!hdr->GetAddr1 ().IsGroup ()) originator->SetSequenceControl (hdr->GetSequenceControl ());
  m_callback (agregate, hdr);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class RegularWifiMac : public WifiMac{
  RegularWifiMac ();
  virtual void Receive (Ptr<Packet> packet, const WifiMacHeader *hdr);
  MacRxMiddle *m_rxMiddle;
  ...
};

RegularWifiMac::RegularWifiMac (){
  m_rxMiddle->SetForwardCallback (MakeCallback (&RegularWifiMac::Receive, this));
  ...
}

void RegularWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr){
  NS_LOG_FUNCTION (this << packet << hdr);
  Mac48Address to = hdr->GetAddr1 ();
  Mac48Address from = hdr->GetAddr2 ();
  if (to != GetAddress ()) return;
  if (hdr->IsMgt () && hdr->IsAction ()){
    NS_ASSERT (m_qosSupported);
    WifiActionHeader actionHdr;
    packet->RemoveHeader (actionHdr);
    switch (actionHdr.GetCategory ()){
      case WifiActionHeader::BLOCK_ACK:
        ...
      default:
        NS_FATAL_ERROR ("Unsupported Action frame received");
        return;
      }
   }
  NS_FATAL_ERROR ("Don't know how to handle frame (type=" << hdr->GetType ());
}

这段代码中包含两个类MacRxMiddle和RegularWifiMac. 首先, MacRxMiddle中有一个回调变量ForwardUpCallback m_callback;, 同时具有两个操作, 用于设置m_callback的SetForwardCallback函数, 及用于处理收包行为的操作Receive函数. 并且, Receive函数最后的语句m_callback (agregate, hdr);, 是一个调用回调函数的语句. 然后, 分析类RegularWifiMac, 它包含一个MacRxMiddle类的实例化指针MacRxMiddle *m_rxMiddle;. 并且, 在初始化时, 通过m_rxMiddle->SetForwardCallback (MakeCallback (&RegularWifiMac::Receive, this));将RegularWifiMac::Receive函数关联刚刚提到的MacRxMiddle中的m_callback. 简单来说, 以上程序使用回调达到效果是, MacRxMiddle::Receive中的m_callback (agregate, hdr);可以替换为RegularWifiMac::Receive (agregate, hdr);. 那么, 到底为什么要使用回调函数, 而不是直接在MacRxMiddle中编写RegularWifiMac::Receive函数呢? 因为RegularWifiMac类需要的是RegularWifiMac::Receive行为, 但是其他类中的MacRxMiddle实例, 需要的可能就是其他收包行为. 这便是回调的魅力.

结束语

虽然new过那么多个object, 然而这并没有什么...

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

推荐阅读更多精彩内容