4
              ------------                       ------------
              | 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”类的连接,我认为交叉引用可能是一种不错的方式(从 OLSR 到 PriQueue 的连接是在 NS2 中使用指针“target_”自动设置的,其类型为 NsObject*)。

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

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

交叉引用机制是从这个页面获得的: 交叉引用如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);
   .....
}

PS:我还尝试将 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() 函数。

4

3 回答 3

1

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

  • OLSR 或某些父级定义recv()使其不是抽象的。
  • 类 Handler 至少有一个虚函数(否则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;
}
于 2010-09-29T17:19:01.053 回答
1
class OLSR : public Agent

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

由于“OLSR”不是从“Handle”派生的,“Handle”到“OLSR”的动态转换失败。您可以仅从多态 Base 到 Derived 而不是不相关的类进行 dynamic_cast。

于 2010-09-29T09:32:31.527 回答
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.
   }

这是类处理程序的实现:

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

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

   target_->recv(p,h); 

为了避免事件调度,直接调用了recv(Packet*, Handler*)PriQueue的函数,结果是错误的。

控件仍然会进入NsObject::handle(),尽管使用target_->recv(p,h)了 ,因为NsObject::handle()函数只接受一个Event*类型参数,Handler*参数总是会丢失。这就是olsr_callback变量始终为 NULL 的原因。(这已经在我的调试过程中得到验证。)

NsObject所以下一步将对NsObject::recv(). target_->recv(p,h):)

再次感谢你的帮助。

于 2010-09-30T07:29:59.620 回答