Перекрестная ссылка и передача этого указателя между классами [NS2 / C ++] - PullRequest
4 голосов
/ 29 сентября 2010
              ------------                       ------------
              | 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.В результате при вызове функции add_rr_ack () из объекта PriQueue строка, обращающаяся к переменной ra_addr_, сгенерирует ошибку сегментации .

(Программа работает нормально, если строка "nsaddr_t addr = ra_addr();" заблокирована)

Механизм перекрестной ссылки получен с этой страницы: перекрестная ссылка, как указано в посте 4

Я думаю, это проблема способа, которым я пытался передать указатель "this" в send_pkt ().Но я не могу понять, что не так.Если у вас есть идеи, пожалуйста, помогите мне.

Любая помощь будет оценена.

Шу.

//------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: Я также пытался изменить recvФункция () в классе PriQueue выглядит следующим образом:

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

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

// Однако в этом случае, когда мы вызываем функцию recv () из send_pkt ().Фактически он вызовет функцию recv () очереди Base, а не функцию recv () PriQueue, как ожидалось.

Ответы [ 3 ]

1 голос
/ 29 сентября 2010

Код ниже работает с моим компилятором.Он выводит «20», которое было значением, которое я дал члену OLSR :: ra_addr_.Несколько неустановленных предположений, которые я должен был добавить, чтобы компилировать вещи:

  • OLSR или некоторый родительский элемент определяет recv(), чтобы он не был абстрактным.
  • Class 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;
}
1 голос
/ 29 сентября 2010
class OLSR : public Agent

Ваш класс OLSR является производным от некоторого класса 'Agent' (который я не знаю, что это). Я предполагаю, что это не один из тех классов, производных от 'Handle' (так как он не показан на диаграмме).

Поскольку «OLSR» не является производным от «Handle», dynamic_cast от «Handle» до «OLSR» завершается ошибкой Вы можете делать dynamic_cast только с полиморфной Base на Derived, а не на несвязанные классы.

0 голосов
/ 30 сентября 2010

Спасибо всем за помощь, 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).:)

Еще раз спасибо за вашу помощь.

Шу

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...