4 Stimmen

Übersetzen von Cross Reference und Weitergabe des This-Zeigers zwischen Klassen [NS2/C++]

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

Liebe alle, ich verwende NS2, um ein Netzwerk-Codierungsprotokoll zu implementieren. Ich stecke jedoch seit Tagen in einem Problem fest, das sich auf die Querverweise zwischen Klassen und die Art und Weise, wie der „this“-Zeiger übergeben wird, bezieht.

Die Klassenhierarchie wird in der obigen Abbildung gezeigt (Bitte entschuldigen Sie, dass es so aussieht, ich bin ein neuer Benutzer dieser Website und darf keine Bilder posten).

Im Programm muss ich eine Verbindung von der Klasse "PriQueue" zur Klasse "OLSR" herstellen, bei der ich denke, dass Querverweise eine gute Möglichkeit sein könnten (Die Verbindung von OLSR zu PriQueue wird automatisch in NS2 mittels des Pointers 'target_', der vom Typ NsObject* ist, festgelegt).

Ein Teil des Codes wird unten gegeben. Das Problem ist jedoch, dass der Zeiger "olsr_callback" immer NULL ist. Als Ergebnis erzeugt der Aufruf der Funktion add_rr_ack() vom Objekt PriQueue einen Sigmenationsfehler.

(Das Programm funktioniert einwandfrei, wenn die Zeile "nsaddr_t addr = ra_addr(); " blockiert ist)

Der Querverweismechnanismus wird von dieser Seite erhalten: Querverweis wie in Post 4 erwähnt

Ich vermute, dass es das Problem der Art und Weise ist, wie ich den „this“-Zeiger in send_pkt() übergeben habe. Aber ich kann nicht herausfinden, was falsch ist. Wenn Ihnen eine Idee einfällt, helfen Sie mir bitte.

Jede Hilfe wird geschätzt.

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
#include

void OLSR::send_pkt() {
    ......
    ......
    target_->recv(p,this);    // 'target_' zeigt zur entsprechenden priqueue-Objekt 
                              // während der Laufzeit
}

Packet* OLSR::add_rr_ack(Packet* p, PriQueue*) {
    ......
    nsaddr_t  addr = ra_addr();     // Erzeugt einen Segmenationsfehler!!!!!
    .......
    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
#include "priqueue.h"

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

PriQueue::recv(Packet* p, Handler* h) {
    ......
    olsr_callback = dynamic_cast(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: Ich habe auch versucht, die recv() Funktion in der Klasse PriQueue wie folgt zu ändern:

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

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

// In diesem Fall ruft der Aufruf der recv() Funktion aus send_pkt() tatsächlich die recv() Funktion der Basisklasse Queue auf, nicht die recv() Funktion von PriQueue, wie erwartet.

1voto

Chubsdad Punkte 23861
class OLSR : public Agent

Ihre Klasse OLSR leitet sich von einer Klasse 'Agent' ab (von der ich nicht weiß, was es ist). Ich gehe davon aus, dass es sich nicht um eine der Klassen handelt, die von 'Handle' abgeleitet sind (da sie nicht im Diagramm angezeigt werden).

Da 'OLSR' nicht von 'Handle' abgeleitet ist, schlägt dynamic_cast von 'Handle' nach 'OLSR' fehl. Sie können dynamic_cast nur von polymorpher Base nach Derived durchführen und nicht zu nicht verwandten Klassen.

1voto

aschepler Punkte 68538

Der folgende Code funktioniert mit meinem Compiler. Es gibt "20" aus, was der Wert war, den ich dem Member OLSR::ra_addr_ zugewiesen habe. Ein paar ungenannte Annahmen, die ich hinzufügen musste, um die Dinge zum Kompilieren zu bringen:

  • OLSR oder ein Elternteil definiert recv(), so dass es nicht abstrakt ist.
  • Klasse Handler hat mindestens eine virtuelle Funktion (ansonsten wäre die Verwendung von Handler* mit dynamic_cast fehlerhaft, und Ihr Compiler sollte sich beschweren).
  • Sie rufen irgendwann OLSR::send_pkt auf. Ich gehe davon aus, dass Sie die Debug-Ausgabefunktion überprüft haben. (Aber vielleicht wird sie mit einem anderen PriQueue-Objekt aufgerufen?)
  • Ignorieren Sie Packet::get(). Das dient nur dazu, mir einen Zeiger zu geben, damit ich Funktionen mit Ihren Signaturen aufrufen kann.

Wenn Sie nicht herausfinden können, warum Ihr Code nicht funktioniert, versuchen Sie immer dies: Machen Sie eine Kopie Ihres gesamten Codes und entfernen Sie dann nach und nach Dinge, bis Sie entweder das Problem eingrenzen oder ein einfaches Beispiel erhalten, das Sie vollständig posten können, um zu fragen, warum es nicht tut, was Sie erwarten.

#include 

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(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;
}

0voto

Edward Punkte 71

Vielen Dank für all eure Hilfe, Chubsdad und aschepler.

Ich habe herausgefunden, wo das Problem liegt.

Normalerweise wird ein Paket als Ereignis in der Simulationstimelinie mit folgender Anweisung geplant:

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

wo p das Paket ist, das in ein Ereignis umgewandelt wird; '0.0' ist die Verzögerungszeit des Ereignisses, in diesem Fall ist sie null; und der Schlüsselparameter, 'target_', ist der Handler, der das Ereignis verarbeiten wird.

Hier ist ein Teil der Klasse NsObject und ihrer Implementierung:

   //----------- 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 meinem Fall wird dies die recv(Packet*,Handler*) der PriQueue-Klasse aufrufen.
   }

und hier ist die Implementierung der Klasse Handler:

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

Basierend auf meinem bisherigen Verständnis von NS2 habe ich versucht,

   target_->recv(p,h); 

zu verwenden, um die Eventplanung zu vermeiden und direkt die Funktion recv(Packet*, Handler*) von PriQueue aufzurufen, was sich als falsch herausstellte.

Die Steuerung wird trotz Verwendung von target_->recv(p,h) immer noch in die NsObject::handle()-Funktion gelangen, da die NsObject::handle()-Funktion nur einen Event*-Typ-Parameter erfordert und der Handler*-Parameter immer verloren geht. So wurde die Variable olsr_callback immer NULL. (Dies wurde in meinem Debugging-Prozess bestätigt.)

Der nächste Schritt wäre also, einige Anpassungen an NsObject vorzunehmen, selbst wenn ich immer noch nicht vollständig verstehe, wie es zur Funktion NsObject::recv() kommt, wenn target_->recv(p,h) verwendet wird. :)

Nochmals vielen Dank für eure Hilfe.

Shu

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X