[英]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.