簡體   English   中英

派生類在C ++中攜帶不同數據類型的最佳方法

[英]Best way for derived classes to carry different data types in C++

在C ++中提供一個接口的最優雅的方法是,該接口接受派生類類型,這些派生類類型帶有不同的數據類型成員,這些成員隨后需要被檢索。 下面的示例說明了這一點,其中Container類提供了用於“發布” Item的方法,該方法將是BaseItem的某種派生變體。 稍后,我想取回派生的Item並提取其值。

我想要的主要事情是讓Container接口(發布和接收)在將來保持不變,同時允許定義和“傳遞”不同的“ Item”派生類型。 模板在某種程度上會更好嗎? 我寧願不使用RTTI。 也許對此有一些簡單,優雅的答案,但是現在我正在努力思考。

class ItemBase {
  // common methods
};

class ItemInt : public ItemBase
{
  private:
    int dat;
  public:
    int get() { return dat; }  
};

class ItemDouble : public ItemBase
{
  private:
    double dat;
  public:
    double get() { return dat; }  
};

class Container {
 public:
   void post(int postHandle, ItemBase *e);      
   ItemBase* receive(int handle); // Returns the associated Item
};

int main()
{
   ItemInt *ii = new IntItem(5);
   Container c;
   c.post(1, ii);

   ItemInt *jj = c.receive(1); 
   int val = jj->get();  // want the value 5 out of the IntItem
}

絕對是通用編程而不是繼承的候選人。 請記住,當您希望對不同數據類型進行相同處理時,泛型(模板)是理想的選擇。 您的ItemInt和ItemDouble類違反了OO設計原則(get()方法根據實際的子類型返回不同的數據類型)。 通用編程就是為此而構建的。 唯一的其他答案是標記數據類型,我個人避免使用類似瘟疫的方法。

您的Container類看起來像一個std :: map。 在我看來,您的ItemBase類只是通用基類“ Object”的另一個名稱,我認為它與void *並沒有多大不同(或優於void *)。 我會避免嘗試在單個容器中包含不同類型的項目。 如果您的設計似乎需要這樣做,那么我會重新考慮您的設計。

怎么樣?

template<typename T>
class Item
{
  private:
    T dat;
  public:
    T get() { return dat; }  
};

class Container {
 public:
   template<typename T>
   void post(int postHandle, Item<T> *e);      

   template<typename T>
   Item<T>* receive(int handle); // Returns the associated Item
};

int main()
{
   Item<int> *ii = new Item<int>(5);
   Container c;
   c.post(1, ii);

   Item<int> *jj = c.receive<int>(1); 
   int val = jj->get();  // want the value 5 out of the IntItem
}

純模板方法不起作用,因為您顯然希望在容器中使用混合類型。 您可以使用Boost的any盡管我認為您需要恢復實際值。 在這種情況下,我認為需要的是一個基類,該基類暴露了類型無關的方法和虛方法以及一個模板化派生類,以容納實際項目:

class Base {
public:
    virtual ~Base() {}
    virtual void post() = 0;
};

template <typename T>
class Item: public Base {
public:
    Item(T const& value): value_(value) {}
    void post() { std::cout << "posting " << this->value_ << "\n"; }
private:
    T value_;
};

這種方法避免了需要為另一個值類型編寫任何派生的Item類。 為了使創建這些野獸更加容易,您可能還希望創建一個合適的創建函數,例如

template <typename T>
std::unique_ptr<Base> make_item(T const& value) {
    return std::unique_ptr<Base>(new Item<T>(value));
}

返回一個std::unique_ptr<Base>以確保釋放分配的對象(如果您不使用C ++ 2011,則可以使用std::auto_ptr<T> )。 可以輕松地將該類型轉換為其他指針類型,例如,轉換為更適合放入容器的std::shared_ptr<Base>

暫無
暫無

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

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