交叉引用并在类之间传递此指针[NS2 / C ++]

时间:2010-09-29 09:13:36

标签: c++ pointers this cross-reference

              ------------                       ------------
              | TclObjct |                       |  Handler |
              ------------                       ------------
                   |__________________________________|
                                   |
                             --------------
                              | NsObject  |---> virtual void recv(Packet*,Handler* callback = 0) = 0;
                             --------------
                                   |
                             --------------
                              | Connector |
                             --------------
                                   |
                      ________________________________
                      |                              |
                      |                         -------------     
                      |                         |   Agent   |
                      |                         -------------
                      |                              |
                      |                         -------------
                      |                         |   OLSR    |
               -------------                    -------------
               |   Queue   |-----> virtual void recv(Packet*, Handler*);
               -------------                    
                      |
               -------------
                | DropTail |
               -------------
                      |
               -------------
                | PriQueue |-----> void recv(Packet* p, Handler* h);
               --------------

亲爱的, 我正在使用NS2来实现网络编码协议。但是我几天都遇到了关于类之间的交叉引用和传递“this”指针的方法的问题。

类层次结构如上图所示(请原谅我看起来像这样,我是这个站点的新用户,不允许发布图像)。

在程序中我必须创建一个从“PriQueue”类到“OLSR”类的连接,我认为交叉引用可能是一个很好的方法(使用指针在NS2中自动设置从OLSR到PriQueue的连接'target_',类型为NsObject *)。

部分代码如下。 但问题是,指针“olsr_callback”始终为NULL。因此,当从PriQueue对象调用函数add_rr_ack()时,访问“ra_addr_”变量的行将生成分段错误

(如果“nsaddr_t addr = ra_addr();”行被阻止,该程序可以正常工作

从此页面获取交叉引用机制: cross reference as stated in post 4

我想这是我试图在send_pkt()中传递“this”指针的方式的问题。但我无法弄清楚出了什么问题。如果您有任何想法,请帮助我。

任何帮助将不胜感激。

舒。

//------OLSR.h--------//
class PriQueue;
class OLSR : public Agent {
    ......
    nsaddr_t ra_addr_;
    void send_pkt();
    ......
public:
    inline nsaddr_t& ra_addr()  { return ra_addr_; }
    Packet* add_rr_ack(Packet*,PriQueue*);
    ......
}

//------OLSR.cc------//
#include<olsr/OLSR.h>
#include<queue/priqueue.h>

void OLSR::send_pkt() {
    ......
    ......
    target_->recv(p,this);    // 'target_' points to the respective priqueue object 
                              // during the runtime
}

Packet* OLSR::add_rr_ack(Packet* p, PriQueue*) {
    ......
    nsaddr_t  addr = ra_addr();     // Generate a segmentation error!!!!!
    .......
    return p;
}
......

//------priqueue.h------//
class OLSR;

class PriQueue : public DropTail {
public:
    void recv(Packet* p, Handler* h);
    ......
    Packet* deque();
    OLSR* olsr_callback;
    ......
}

//------priqueue.cc------//
#include<olsr/OLSR.h>
#include "priqueue.h"

PriQueue::PriQueue() : DropTail(),olsr_callback(NULL) {......}

PriQueue::recv(Packet* p, Handler* h) {
    ......
    olsr_callback = dynamic_cast<OLSR*>(h);
    //Debug
    printf("Packet received through recv() in PriQueue. \n");
    ......
}

PriQueue::deque() {
   .....
   Packet* p = q_->deque();       

   if(olsr_callback == NULL)  printf("CALLBACK is NULL. \n");
   Packet* p1 = olsr_callback->add_rr_ack(p);
   .....
}

P.S:我还尝试更改类PriQueue中的recv()函数,如下所示:

//------priqueue.h------//
void recv(Packet* p, OLSR* h);

// ------priqueue.cc-----//
void PriQueue::recv(Packet* p, OLSR*h) {
   ......
   olsr_callback = h;
   ......
}

//    但是,在这种情况下,当我们从send_pkt()调用recv()函数时。它实际上将调用基类Queue的recv()函数,而不是预期的PriQueue的recv()函数。

3 个答案:

答案 0 :(得分:1)

class OLSR : public Agent

你的类OLSR派生自某个类'Agent'(我不知道它是什么)。我假设这不是从'Handle'派生的那些类之一(因为它没有在图中显示)。

由于'OLSR'不是来自'Handle',因此'Handle'到'OLSR'的dynamic_cast失败。您可以执行dynamic_cast,从多态Base到Derived,而不是不相关的类。

答案 1 :(得分:1)

以下代码适用于我的编译器。它输出“20”,这是我给成员OLSR :: ra_addr_的值。我必须添加一些未说明的假设来编译:

  • OLSR或某些父级定义recv(),因此它不是抽象的。
  • 类处理程序至少有一个虚函数(否则使用Handler*和dynamic_cast会形成错误,编译器应该抱怨)。
  • 您可以在某个时候调用OLSR :: send_pkt。我假设你已经检查了它的调试输出线。 (但也许它是用不同的PriQueue对象调用的?)
  • 忽略Packet::get()。那只是给我一个指针,所以我可以调用与你的签名匹配的函数。

如果你无法弄清楚你的代码无法正常工作的原因,请尝试这样做:复制所有代码,然后一次删除一些内容,直到找出问题或得到一个简单的例子您可以完整地发布并询问为什么它没有达到预期效果。

#include <iostream>

class Packet {
public:
    static Packet* get() { return &dummy_; }
private:
    static Packet dummy_;
};
Packet Packet::dummy_;

class Handler {
public:
    virtual ~Handler() {}
};

class NsObject : public Handler {
public:
    virtual void recv(Packet*, Handler* callback = 0) = 0;
};

class Connector : public NsObject {};

class Queue : public Connector {
public:
    virtual void recv(Packet*, Handler*) {}
};

class DropTail : public Queue {};

class OLSR;

class PriQueue : public DropTail {
public:
    inline PriQueue() : DropTail(), olsr_callback(NULL) {}
    void recv(Packet* p, Handler* h);
    Packet* deque();
private:
    OLSR* olsr_callback;
};

class Agent : public Connector {};

class OLSR : public Agent {
public:
    explicit OLSR(int ra_addr) : Agent(), ra_addr_(ra_addr) {}
    inline int ra_addr() { return ra_addr_; }
    void send_pkt(PriQueue* q);
    Packet* add_rr_ack(Packet* p, PriQueue*);
    virtual void recv(Packet*, Handler*) {}
private:
    int ra_addr_;
};

void PriQueue::recv(Packet* p, Handler* h) {
    olsr_callback = dynamic_cast<OLSR*>(h);
}

Packet* PriQueue::deque() {
    return olsr_callback->add_rr_ack(Packet::get(), this);
}

void OLSR::send_pkt(PriQueue* q) {
    q->recv( Packet::get(), this );
}

Packet* OLSR::add_rr_ack(Packet* p, PriQueue*) {
    std::cout << ra_addr() << std::endl;
    return p;
}

int main() {
    PriQueue q;
    OLSR olsr(20);
    olsr.send_pkt(&q);
    q.deque();

    return 0;
}

答案 2 :(得分:0)

谢谢大家的帮助,Chubsdad和aschepler。 我找到了问题所在。

通常,使用以下语句将数据包安排为模拟时间线上的事件:

Scheduler::instance().schedule(target_,p,0.0);

其中p是转换为事件的数据包; '0.0'是事件的延迟时间,在这种情况下它是零;而关键参数'target_'是处理事件的处理程序。

这是NsObject类及其实现的一部分:

   //----------- object.h ----------//
    class NsObject : public TclObject, public Handler {
    public:
       NsObject();
       virtual ~NsObject();
       virtual void recv(Packet*, Handler* callback = 0) = 0;
    protected:
       void handle(Event*);
    }

   //------------ object.cc -----------//
    void NsObject::handle(Event* e)
   {
       recv((Packet*)e);   // In my case, this will call the recv(Packet*,Handler*) of PriQueue class.
   }

这里是类Handler的实现:

   class Handler {
   public:
       virtual ~Handler() {}
       virtual void Handler(Event* event) = 0;
   }

根据我之前对NS2的理解,我尝试使用

   target_->recv(p,h); 

避免事件安排,并直接调用PriQueue的recv(Packet*, Handler*)函数,结果证明是错误的。

尽管使用NsObject::handle(),控件仍会输入target_->recv(p,h),因为NsObject::handle()函数仅采用Event*类型参数,Handler*参数永远都会迷失。这就是olsr_callback变量总是为NULL的方式。 (这已在我的调试过程中得到验证。)

因此,下一步是对NsObject进行一些调整,即使我仍然不完全理解在使用NsObject::recv()时它最终如何输入功能target_->recv(p,h)。 :)

再次感谢您的帮助。