簡體   English   中英

擴展 C++ class / struct 數據成員的更好方法

[英]Better way to extend data members of C++ class / struct

我一次又一次地遇到這個問題......仍然沒有一個滿意的答案......

尤其是當我把class放到一個容器里的時候,后面在具體的處理過程中需要記錄容器中每一個元素的更多信息,但是處理完之后就不需要這些額外的信息了....

我經常發現一些庫試圖通過在它們的數據結構中定義一個 void* 來提供用戶定義的數據結構擴展來解決上述情況。 與本問答中描述的相同。 但是會產生memory/resource handling problem...等問題,我覺得這種方式容易出錯。

在面向對象編程的現代,我正在考慮使用 inheritance 和多態性。 在容器中使用基類的指針,但是我必須將派生類的訪問器添加到基類 class 中。這有點奇怪......

在 C++ 中,有沒有其他更好的方法來擴展類的屬性,同時保持容器的可比性?

在不實際損害 object 本身完整性的情況下存儲有關 object 的額外數據的最佳方法是在容器中存儲一對數據。

struct User { ... };
struct ExtraData { ... };
typedef std::pair<User, ExtraData> UserAndExtraData;

現在我可以在 C++ 中創建一個容器類型,它將兩條信息存儲在一起,而不會影響任何一種類型的獨立性。

std::vector<UserAndExtraData> vector;

我會研究Decorator Pattern 您可以在處理對象時對其進行裝飾,然后將裝飾過的對象扔掉。 如果有大量共享數據,您還可以查看FlyWeight 模式

“用戶”可以通過模板參數進行擴展。 例如,

template <typename... Extra>
struct User : Extra...
{
    ...
};

struct ExtraData {...};
struct ExtraExtraData {...};

using ExtraUser = User<ExtraData>;
using MoreExtraUser = User<ExtraData, ExtraExtraData>;

如果您的對象在向量中,那么一個簡單的方法是制作一個平行向量:

void doSomething(const vector<MyObject>& my_objects)
{
  vector<ExtraData> extra_data;
  int n_objects = extra_data.size();
  extra_data.reserve(n_objects);
  for (int i=0; i!=n_objects; ++i) {
    extra_data.push_back(calcExtraData(my_objects[i]));
  }
  // now use my_objects[i] and extra_data[i] together.
  // extra data goes away when the function returns.
}

您不必修改您的原始對象,而且效率很高。

如果您有其他容器類型,您可以使用 map:

void doSomething(const set<MyObject>& my_objects)
{
  map<MyObject*,ExtraData> extra_data;
  set<MyObject>::const_iterator i=my_objects.begin(), end=my_objects.end();
  for (;i!=end;++i) {
    extra_data[&*i] = calcExtraData(*i);
  }
  // now use extra_data[&obj] to access the extra data for obj.
  // extra data goes away when the function returns.
}

這不如向量有效,但您仍然不必修改原始類。

但是,如果底層容器在處理過程中可能發生變化,那么維護並行結構就會變得更加困難。

在面向對象編程的現代,我正在考慮使用 inheritance 和多態性。 在容器中使用基類的指針,但隨后我必須將派生類的訪問器添加到基類 class 中。這有點奇怪......

使用 inheritance 時,您不需要在基 class 中放置指向派生 class 的指針。您只需要強制轉換為派生 class。問題是當數據存儲在基礎對象中時,將數據放入派生對象中 - 你只有當它們被創建為派生類型時才能轉換它們,即使您的集合將它們作為基類型保存。 (如果它們被創建為派生類型,那么就強制轉換!)

因此,如果您有 BaseC 的集合,則可以創建一個新的 class DerivedC,它具有一個采用 BaseC 的復制構造函數。 您可以將 BaseC object 復制到其中,對 DerivedC 對象執行處理,然后將這些復制回 BaseC object 進行存儲。 這使用享元模式。 請注意,如果您有一組 BaseC 對象,則不能假裝它們是 DerivedC 類,因為它們沒有存儲空間來保存所有數據成員,您需要創建新的 DerivedC 對象。

或者,創建一個新的 class 僅用於處理,其中包含對基本 class 對象的(智能指針)引用,復制引用,執行處理,完成后刪除處理對象。

一個簡單的選擇是添加一個代表“額外數據”的類型參數......

template<class ExtraDataType>
struct MyExtensibleContainer
{
    ...
    ExtraDataType extra;
};

或許如果您指出此解決方案不夠充分的原因,那么真正的需求就會出現。

int 和 void* 的示例:

struct IntOrVoid
{
};

struct IntOrVoid1 : IntOrVoid
{
    int x;
};

struct IntOrVoid2 : IntOrVoid
{
    void* x;
};

typedef shared_ptr<IntOrVoid> PIntOrVoid;

then use MyExtensibleContainer<PIntOrVoid>

或者:

union IntOrVoid
{
    int x_int;
    void* x_voidp;
};

then use MyExtensibleContainer<IntOrVoid>

您描述的問題與添加“額外”數據類型無關。 您所描述的問題與持有可以具有許多異構類型之一的變體類型有關。 有很多方法可以做到這一點,這是一個更普遍的問題。

暫無
暫無

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

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