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 への接続は、ポインタ「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() 関数を呼び出すとき。実際には、PriQueue の recv() 関数ではなく、基本クラス Queue の recv() 関数を呼び出します。

4

3 に答える 3

1

以下のコードは私のコンパイラで動作します。これは、メンバー OLSR::ra_addr_ に指定した値である "20" を出力します。物事をコンパイルするために追加しなければならなかったいくつかの明言されていない仮定:

  • OLSR または一部の親が定義しrecv()ているため、抽象的ではありません。
  • クラス ハンドラーには少なくとも 1 つの仮想関数があります (それ以外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」から派生したクラスの 1 つではないと思います (図には表示されていないため)。

'OLSR' は 'Handle' から派生していないため、'Handle' から 'OLSR' への dynamic_cast は失敗します。ポリモーフィック Base から Derived のみに dynamic_cast を実行でき、無関係なクラスには実行できません。

于 2010-09-29T09:32:31.527 に答える
0

チャブスダッドとアシェプラー、助けてくれてありがとう。私は問題がどこにあるかを見つけました。

通常、パケットは、次のステートメントを使用してシミュレーション タイムラインのイベントとしてスケジュールされます。

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 の関数を直接呼び出します。

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 に答える