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

发布于 2024-09-25 12:33:56 字数 4115 浏览 9 评论 0原文

              ------------                       ------------
              | 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 的连接是使用指针“target_”在 NS2 中自动设置的) ,其类型为 NsObject*)。

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

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

交叉引用机制从此页面获得: 交叉引用如帖子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()函数。

              ------------                       ------------
              | 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);
               --------------

Dear all,
I am using NS2 to implement a network coding protocol. But I have been stuck on a problem for days regarding to cross reference between classes and the way to pass the "this" pointer.

The class hierarchy is shown in the above figure (Please excuse me it looks like that, I am a new user of this site, and is not allowed to post images).

In the program I have to create a connection from the "PriQueue" class to the "OLSR" class, which I think cross reference might be a nice way (The connection from OLSR to PriQueue is automatically set in NS2 using the pointer 'target_', which is of type NsObject*).

Part of the code is giving below.
But the problem is, the pointer "olsr_callback" is always NULL. As a result, when calling function add_rr_ack() from the PriQueue object, the line accessing the 'ra_addr_' variable will generates a segmentation error.

(The program works fine if the line "nsaddr_t addr = ra_addr(); " is blocked)

The cross reference mechanism is obtained from this page:
cross reference as stated in post 4

I guess it is the problem of the way I tried to pass the "this" pointer in send_pkt(). But I can't figure out what is wrong. If you have any idea in mind, please help me.

Any help will be appreciated.

Shu.

//------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: I also tried to change the recv() function in class PriQueue as follows:

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

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

//
However, in this case, when we call the recv() function from send_pkt(). It will actually invoke the recv() function of the base class Queue, not the recv() function of the PriQueue as expected.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我也只是我 2024-10-02 12:33:56
class OLSR : public Agent

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

由于“OLSR”不是从“Handle”派生的,因此“Handle”到“OLSR”的dynamic_cast 失败。您只能从多态基类到派生类进行动态转换,而不能对不相关的类进行动态转换。

class OLSR : public Agent

You class OLSR is derived from some class 'Agent' (which I don't know what it is). I assume that is not one of those classes derived from 'Handle' (since it is not shown in the diagram).

Since 'OLSR' is not derived from 'Handle', dynamic_cast of 'Handle' to 'OLSR' fails. You can do dynamic_cast from polymorphic Base to Derived only and not to unrelated classes.

养猫人 2024-10-02 12:33:56

下面的代码适用于我的编译器。它输出“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;
}

The code below works with my compiler. It outputs "20", which was the value I gave to the member OLSR::ra_addr_. A few unstated assumptions I had to add to get things compiling:

  • OLSR or some parent defines recv() so that it's not abstract.
  • Class Handler has at least one virtual function (otherwise using Handler* with dynamic_cast would be ill-formed, and your compiler should complain).
  • You call OLSR::send_pkt at some point. I assume you have checked for its debug output line. (But maybe it's being called with a different PriQueue object?)
  • Ignore Packet::get(). That's just there to give me a pointer so I can call functions matching your signatures.

If you can't figure out why your code isn't working, always try this: Make a copy of all your code, and then remove things a bit at a time until you either pinpoint the problem or get a simple example that you can post in entirety and ask why it doesn't do what you expect.

#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;
}
情话难免假 2024-10-02 12:33:56

感谢你们所有人的帮助,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); 

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

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

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

再次感谢您的帮助。

Thank you all for your help, Chubsdad and aschepler.
I have found where the problem is.

Normally, a packet is scheduled as an event on the simulation timeline using the following statement:

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

where p is the packet which is casted to a event; '0.0' is the delay time of the event, in this case it is zero; and the key parameter, 'target_' is the handler which will process the event.

Here is part of the class NsObject and its implementation:

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

and here is the implementation of class Handler:

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

Based on my previous understanding about NS2, I tried to use

   target_->recv(p,h); 

to avoid event scheduling, and directly call the recv(Packet*, Handler*) function of PriQueue, which turned out to be wrong.

The control will still enter the NsObject::handle(),despite of using target_->recv(p,h), as the NsObject::handle() function takes only a Event* type parameter, the Handler* parameter will always be lost. That is how the olsr_callback variable turned out to be always NULL. (This has been verified in my debugging process.)

So the next step would be make a few adjustments to NsObject, even if I still don't fully understand how it ends up entering function NsObject::recv() when using target_->recv(p,h). :)

Thanks again for your help.

Shu

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文