七 模板與泛型程式設計 條款41 43

2022-08-16 02:33:17 字數 3037 閱讀 5064

從乙個函式解讀隱式介面和編譯期多型:

templatevoid doprocessing(t &w)

}

隱式介面:從這段**來看,w物件要支援size,normalize,swap函式,也要支援比較函式,這就是t必須支援的一組隱式介面。

編譯期多型:涉及w物件的任何呼叫,都有可能造成template的具現化。這樣的具現化發生在編譯期,也就是編譯期多型。

tips:上述的具現化也就是我們呼叫的時候,具體得到t的型別是什麼,然後會呼叫相應的函式。

不一樣之處

在上述**看來,t型別的物件要支援size函式。但是這個函式必須返回乙個數值型別嗎?不一定!只需要返回的型別為x的物件,x+10能夠呼叫乙個operator>即可!更甚至,不需要返回乙個x的型別,返回乙個y型別,此y型別可以隱式轉為x即可!

classes和templates都支援介面和多型。

對classes而言介面是顯式的,以函式簽名為中心。多型是通過virtual函式發生於執行期。

對templates引數而言,介面是隱式的,奠基於有效表示式。多型是通過templates具現化和函式過載解析發生於編譯期。

事實上,使用模板時有兩種關鍵字寫法:

templateclass widget;

templateclass widget;

這兩種寫法毫無區別!但是在其它情況,typename還有別的用途。

老規矩,我們先看**:

templatevoid print2nd(const c &container)

}

從屬名稱:template內出現的名稱如果依賴於某個template引數,稱之為從屬名稱。如上述的iter,它型別是c::const_iterator,取決於引數c的型別。

巢狀從屬名稱:如果從屬名稱在class內呈巢狀狀,就稱為巢狀從屬名稱。如c::const_iterator就是個巢狀從屬名稱。實際上這還是個巢狀從屬型別名稱,它表示的是乙個型別。

編譯器沒有我們想象中的那麼靈活,使用巢狀從屬名稱可能會給編譯器帶來解析困難。如果我們在上述函式的函式體中有乙個這樣的語句:

c::const_iterator *x;
我們本意是想宣告乙個x的迭代器指標,但是編譯器可能不那麼想。它可能想的是const_iterator這個變數和x變數相乘!對,就是把 * 看成了乘號而不是乙個指標型別。也就是說,如果解析器在template中遭遇乙個巢狀從屬名稱,它便假設這不是個型別,除非你告訴它是。

解決方法:typename關鍵字

使用typename,如:

typename c::const_iterator *x;
在宣告前面加上關鍵字typename就可以讓編譯器把c::const_itrator當作乙個型別來看。

實際上,我在vs2013中測試的時候,在此編譯器中是不需要這樣宣告的。

乙個例外

class derive : public base::nested  // 無typename關鍵字

};

以上**可以清楚帶我們看到哪些時候要用typename,哪些時候不用。

宣告template引數時,字首關鍵字class和typename可互換。

請使用關鍵字typename標識巢狀從屬型別名稱,但不得在base class list或member initialization list內以它作為base class的修飾符。

先考慮一段**:

class companya

void senencrypted(string &msg) };

class companyb

void senencrypted(string &msg) };

class msg

string str;

};templateclass base

};templateclass derived : public base < t >

};

按照作者在書上說法,這段應該是編譯不過的。原因在於derived類中呼叫了sendclear函式。

原因它繼承的基類是乙個模板類,不到具現化的時候無法知道t的型別是什麼,更準確的說是不知道它是否有乙個sendclear的成員函式。所以編譯器不會到基類的作用域中去尋找是否有這個函式。

本質原因則是因為編譯器無法知道是否有個模板類,它是專屬的全特化版本,裡面是去掉了sendclear型別的。所以編譯器拒絕這個呼叫。因為不到具現化,誰也不知道這個函式是否真的存在。

問題我在vs2013中測試,上段**是可以正確執行的:

是否此條款已經過時了呢?現在的編譯器是不是可以正確的判斷了呢?這個我現在還不能分辨清楚,以後學編譯上的東西會再看看。

處理方法:

如果是按照作者書上所說的,那麼作者同時也提供了三種方法來解決(告訴編譯器有這個東西,讓它去尋找):

(1) 在呼叫之前加上this,編譯器就會去基類尋找,否則不會。

(2) 使用using宣告式,讓編譯器去base class中去尋找。

(3) 呼叫前加上base類的作用域。即base::function.

可在derived class templates內通過「this->」指涉base class templates內的成員名稱,或借由乙個明白寫出的「base class資格修飾符」完成。

Effective C (七)模板與泛型程式設計

七 模板與泛型程式設計 條款41 了解隱式介面和編譯器多型 1 物件導向 1 顯式介面 型別必須支援class的介面,在原始碼中明確可見。基於函式簽名式 2 執行期多型 對於某些virtual成員函式,執行時根據動態型別決定呼叫哪個函式 2 template及泛型程式設計 1 隱式介面 型別支援的介...

模板與泛型程式設計

模板是泛型變成的基礎。泛型程式設計 編譯與型別無關的 是一種復用的方式,模板分為模板函式和模板類。模板函式是乙個通用的函式模板,而不是為每一種型別定義乙個新函式,乙個函式模板就像乙個公式,針對不同型別函式生成不同的函式版本。關鍵字 template 以 template 開始,後面跟乙個模板引數列表...

模板與泛型程式設計

泛型程式設計 編寫與型別無關的通用 是 復用的一種手段。模板是泛型程式設計的基礎。函式模板代表了乙個函式家族,該函式模板與型別無關,在使用時被引數化,根據實參型別產生函式的特定型別版本。模板的格式 template 返回值型別 函式名 引數列表 模板分為類模板和函式模板 模板它本身並不是函式,是編譯...