[英]C++ templates with derived classes
我正在寫一個庫,其中有一個BaseClass類。 使用該庫的任何人都將創建自己的從BaseClass繼承的類。 我有另一個類,稱之為Manager,它包含一個BaseClass指針向量,該指針可以容納從BaseClass派生的任何對象。
Manager類必須處理添加到其BaseClass向量中的任何對象的創建和銷毀。 這是因為可以隨時刪除矢量中的任何對象,並且Manager本身也可以刪除。 因此,該庫的用戶無法通過將對象傳遞給從BaseClass派生的現有對象的指針來向Manager的baseClass向量添加對象。 好吧,實際上,我可以允許用戶這樣做。 但這將涉及復制一個虛擬對象,而我寧願不這樣做。
為了解決這個問題,我正在嘗試使用模板函數。 嘗試將其添加到Manager的向量時,用戶應傳遞從BaseClass派生的對象的類型。 這就是我目前所擁有的。
//Manager.h
#include <vector>
#include "BaseClass.h"
#include <typeinfo>
class Manager {
//Vector holding pointers to any objects inherited from BaseClass
vector<BaseClass*> baseClasses;
//Template function that needs to add NEW object to baseClass vector
//This I'm having problems with
template<class T>
BaseClass* Add() {
BaseClass* baseClass = new T();
baseClasses.push_back(baseClass);
return baseClass;
}
//Template function that gets object from baseClass vector
//This works fine
template<class T>
BaseClass* Get() {
for (int i = 0; i < baseClasses.size(); i++) {
if (typeid(*baseClasses[i]) == typeid(T)) {
return baseClasses[i];
}
}
return NULL;
}
};
例如,當添加到Manager的baseClass向量中或從中獲取對象時,用戶應執行此操作。 DerivedClass從BaseClass派生
Manager manager;
//Add a new DerivedClass object to Manager's vector
manager.Add<DerivedClass>();
//Get a pointer to the DerivedClass object that was just added
DerivedClass* derivedClass = (DerivedClass*)manager.Get<DerivedClass>();
我的Get()函數可以正常工作。 我需要知道的是,如何使Add()函數正常工作? 幫助將不勝感激。
您的設計還有很多地方不清楚,但是如果問題是您是否可以強制成員函數templa Add
中的類型T
可以強制從BaseClass
派生,則選項很簡單:
BaseClass* baseClass = new T();
我會選擇前兩個。 靜態斷言可以拼寫為:
static_assert(std::is_base_of<BaseClass,T>::value);
SFINAE的技巧,我真的會避免,因為它會使代碼更加混亂,但可以實現為:
template <class T>
typename std::enable_if<std::is_base_of<BaseClass,T>::value,T*>::type
Add() {
baseClasses.push_back(new T());
return baseClasses.back();
}
(請注意,我將返回類型更改為T*
,對象是T
,為什么返回BaseClass*
?這同樣適用於Get
函數,當您知道對象確實是真正的對象時,返回BaseClass*
毫無意義。一個T
)
現在,實際問題要復雜得多,因為您的設計正在積極地避免所有權的考慮,而您不應這樣做。 考慮對象的所有權,並確保有明確的所有者(或資源是共享的)。 一旦知道誰擁有對象,就為其余代碼創建協議,以在需要刪除對象時通知所有者。 如果您允許任何代碼刪除持有的指針,那么您很快就會遇到未定義的行為。
其他較小的問題可能包括以下事實:您強制所有組件都具有默認構造函數,該構造函數可能適用或不合適。 您可以通過使用帶有指針的非模板化Add
並允許調用方按其喜歡的方式創建對象,來簡化此限制。
使用typeid
通常是一種代碼嗅覺,我也不認為這是例外,也許您可以通過設計一個可以詢問對象是什么的類型層次結構來更好,而不是運行typeid
。 如果您真的確定要根據類型創建接口,請考慮使用dynamic_cast
是否會更好。 它會更加低效,但是如果您具有多個繼承級別,它將使您將派生最多的對象作為中間對象返回
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.