簡體   English   中英

偵聽器類的繼承者-偵聽類的const或非const引用?

[英]Listener class inheritor - const or non-const reference to class listened to?

代碼庫的一個非常常見的模式是這樣的Listener事件:

 class Frobulator
 {
 public:
      class Listener
      {
      private:
          // only frobulators can frob
          friend class Frobulator;
          virtual void onFrobbed() = 0;
      }

      void maybeFrob()
      {
          // assume we always frob, but maybe we only do it sometimes
          // and the caller won't know if a call will do it
          for (auto& l: listeners)
          {
               l->onFrobbed();
          }
      }

      void addListener(Listener* l)
      {
           listeners.push_back(l);
      }

 private:
     std::vector<Listener*> listeners;
 }

然后,一個類繼承了Listener並可以向Frobulator注冊為偵聽Frobulator Frobulator一些來電者(不一定聽眾)的調用后frobs,聽眾會被告知。

我真正的問題是,偵聽器是否應該“內部”偵聽,因此需要對Frobulator的非常量引用,但需要使用private Listener性質進行管理?

 class FrobReactor: private Frobulator::Listener
 {
 public:
      FrobReactor(Frobulator& frobulator_)
           frobulator(frobulator)
      {
           frobulator.addListener(this);
      }

 private:
      void onFrobbed() override
      {
           // react!
      }

      Frobulator& frobulator;
 }

 // and externally ...
 Frobulator theFrobber;
 FrobReactor reactor(theFrobber);
 theFrobber.maybeFrob();

還是應該讓偵聽器采用const引用(如果不需要,甚至不需要引用), FrobReactor承認FrobReactor不會修改Frobulator ,但要宣傳它是Frobulator::Listener並期望客戶端代碼能夠把它掛起來:

class FrobReactor: public Frobulator::Listener
{
public:
    FrobReactor(const Frobulator& frobulator_):
        frobulator(frobulator_)
    {
    }

private:
    void onFrobbed() override
    {
        // react!
    }

    const Frobulator& frobulator;
}

 // and externally
 Frobulator theFrobber;
 FrobReactor reactor(theFrobber);
 theFrobber.addListener(&reactor);
 theFrobber.maybeFrob();

另外,也可以將addListener方法設置為const並使偵聽器列表mutable ,然后第一個方法也可以與非const引用一起使用,但這聽起來像是一種hack。

是否有“正確”的方法來做到這一點?

我不會在FrobReactor中存儲對觀察到的(或監聽到的)Frobulator的引用。 相反,我會將對Frobulator實例的const引用傳遞給onFrobbed方法。

class Listener
{
private:
    // only frobulators can frob
    friend class Frobulator;
    virtual void onFrobbed(const Frobulator& frobulator) = 0;
}

並且, maybeFrob改編:

void maybeFrob()
{
    // assume we always frob, but maybe we only do it sometimes
    // and the caller won't know if a call will do it
    for (auto& l: listeners)
    {
        l->onFrobbed(*this);
    }
}

至於addListener是否應為const(因此,偵聽器的向量是否應為可變的),這取決於您要實現的目標。 我同意這感覺很棘手,但另一方面,如果要確保API的客戶端僅處理const Frobulators,則這是一種實現方法。 另一個方法是在您的API中的某處有一個方法,該方法可以將偵聽器添加到Frobulator中,如下所示:

void addListener(const Frobulator& frobulator, Frobulator::Listener& listener) {
    Frobulator& nonConst = // obtain non-const reference to this frobulator
    nonConst.addListener(listener);
}

這實際上取決於您的設計。 否則,如果您要做的就是保護偵聽器免於修改Frobulator,那么將const引用傳遞給'onFrobbed方法似乎就足夠了。

最后,我將如下更改addListener

void addListener(Listener& listener)
{
    listeners.push_back(&listener);
}

這是一個很小的變化,但是除非有其他原因傳遞指針,否則我只希望在轉讓所有權時傳遞指針。 當然,您必須確保在任何一種情況下都不會刪除您的偵聽器(由於超出范圍)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM