簡體   English   中英

C ++模板和子類?

[英]C++ Templates and Subclasses?

所以,我正在學習C ++,而且我遇到了一些我知道如何用Java做的事情,而不是用C ++ :)。

我有一個容器對象的模板,定義如下:

template <class T>
class Container {
    vector<T> contained;

    public:

    void add(T givenObject) {
        this->contained.push_back(givenObject);
    }

    T get(string givenIdentifier) throw (exception) {
        for (int i = 0; i < this->contained.size(); i++) {
            if (this->contained[i].getIdentifier() == givenIdentifier) {
                return this->contained[i];
            }
        }
        throw new exception("An error has occured which has caused the object you requested to not be found. Please report this bug.");
    }

    bool empty() {
        return this->contained.empty();
    }

    bool identifierExists(string givenIdentifier) {
        for (int i = 0; i < this->contained.size(); i++) {
            if (this->contained[i].getIdentifier() == givenIdentifier) {
                return true;
            }
        }
        return false;
    }
};

這實際上非常有效,只有一個小問題。 它歸結為兩行:第一行是模板定義,第二行是

this->contained[i].getIdentifer()

在Java中,當聲明Generic(模板)時,可以定義一個超類/接口,T的所有成員必須擴展它才能不創建錯誤。 但是,我不確定在C ++中這樣做的方法,我擔心的是將這里的實現耦合到一個可能沒有定義的getIdentifier方法是糟糕的設計。

現在,如果是這樣的話,這不是一個大問題,這只是一個幫助我學習語言的挑戰項目,但我喜歡嘗試做正確的事情。 有辦法做我想的嗎? 我知道你可以用原語來做,例如:

template <int T>

是有效的,但是當我嘗試使用用戶定義的類時,我收到編譯器錯誤。 有什么建議么?

您不可能對模板類型參數設置人為限制。 如果給定的類型不支持您使用它的方式,您將收到編譯器錯誤。 一個名為“概念”的功能,基本上允許這個,將被添加到下一個C ++標准,但由於時間限制,它被推遲到下一個標准。 如果T沒有可見的getIdentifier()函數,則實例化將不會編譯。

模板參數需要在編譯時推導出來。 template<int T>有效,因為第一個模板參數是一個整數; 你可以使用任何常量整數來實例化它。 如果您嘗試將其與非const整數變量一起使用,則無法編譯。 類的實例不是編譯時常量,因此不能使用它。

你已經得到了其他幾個答案,兩者都很好(特別是@dauphic's,IMO)。 我只是補充一點,你給出的代碼看起來非常像是對std::map的低效模仿。 在大多數情況下, std::map可能會更好。 如果你查看它的界面,它還會向你展示一種方法來解決你的容器直接指定getIdentifier() - 而不是直接使用像getIdentifier()這樣的東西,它使用默認為std::less<T>的比較函數std::less<T> ,它將(反過來)使用T::operator< - 但如果您願意,也可以指定完全不同的比較函子。

我還應該指出,雖然其他人已經指出如果你使用getIdentifier (或其他)你會得到一個編譯錯誤,並嘗試實例化一個不提供它的類。 但是,我覺得有必要警告你,你得到的錯誤信息可能很長,很復雜,而且很難破譯。 這是特別容易,如果有這確實有一些其他類型getIdentifier可用的成員。 在這種情況下,您得到的錯誤消息說“無法從type A轉換為type B ”,其中type A是您用於實例化容器的任何類型, type B是發生的任何type B (通常完全不相關)類型擁有一個getIdentifier成員。 發生的事情是編譯器看到你已經使用了getIdentifier ,並且看到type B有那個,所以它試圖將你的type A對象轉換為type B對象,並發現它不能,所以就是它所告訴的你在錯誤信息中。

PS是的,我知道這不僅僅是一個評論,而是一個答案。 我為此道歉,但它不會真正適合評論。

你不需要做任何事情。 如果contained[i]沒有getIdentifer()函數,則會出現編譯時錯誤(就像在Java中使用接口一樣,就像在使用模板之外一樣)。

詳細說明:如果你要寫,

 int x = 10;
 long id = x.getIdentifer();

這將被視為“糟糕的設計”。 這只是一個錯誤,編譯器會抓住它。 這正是你的例子中會發生的事情。

C ++在編譯時多態(即模板)和運行時多態(即繼承)之間繪制了一條相當明顯的界限。 因此語言不支持您想要做的事情。

執行您正在做的事情的一種典型做法是除了T之外還提供可以獲取給定T的標識符的類型。這將兩種行為分離為兩種類型,您可以指定(英語)必須的接口實施。

template <class T, class StringIdForT>
class Container 
{
  ...
   bool identifierExists(string givenIdentifier) 
   {
        StringIdForT idGetter;
        for (int i = 0; i < this->contained.size(); i++) 
        {
            if (idGetter.getIdentifier(this->contained[i]) == givenIdentifier) 
            {
                return true;
            }
        }
        return false;
   }  
};

您有類似的問題,StringIdForT仍然必須定義指定的方法

暫無
暫無

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

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