簡體   English   中英

具有派生類的C ++模板

[英]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();
  • 添加一個靜態斷言以使其更加明顯
  • 使用花哨的SFINAE技巧從重載集中刪除該函數

我會選擇前兩個。 靜態斷言可以拼寫為:

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.

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