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的始末请参见学习:

  • Standard_Template_Library
  • STL
    Reference
  • STL’s
    Guide
  • 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;,
同时负有两单操作, C++用于设置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++