標籤:effective c++ c++ 筆記
//#45 運用成員函數模版接受所有相容類型
{
/* 1:當你使用智能指標的時候,會發生一個問題,想把一個子類的對象賦給基類的指標變得不可能了,
因為智能指標指定了的是基類的類型,而賦給它的是一個它的子類的對象。
2:解決辦法,使用成員函數模版,可以分別對拷貝建構函式和賦值操作進行模版化: */
template<class T>
class SmartPtr
{
public:
//為了防止什麼不管什麼類型都來進行轉換,可以使用一個get()函數來防止這樣的情況。
//這樣只有指標存在隱式轉換才會進行轉換,否則就報錯了。
template<class U>
SmartPtr(const SmartPtr<U>& other): heldPtr(other.get())
T* get()const { return heldPtr;}
template<class U>
SmartPtr<T>&operator=(const SmartPtr<U>& other)
{
heldPtr = other.get();
return *this;
}
};
/* 3:你聲明的泛化的拷貝建構函式和賦值函數並不能阻止編譯器為你產生 正常版本的這兩個函數
所以如果想要控制傳入一樣類型時的情況:也就是U等於T時,你必須自己實現正常版本的函數。*/
}
//#46 需要類型轉換時請為模版定義非成員函數
{
// 1:考慮#24下的非成員函數的隱式類型轉換,如果現在加上template,那麼就行不通了,看起來像這樣:
template<class T>
const Rational<T> operator*(const Rational<T>& r1, const Rational<T>& r2)
{ ...}
/* 如果你有一個Rational<int>類型的 Ra,並且做了這樣的運算 Ra * 6,抱歉,不能通過編譯
這是因為編譯器只能找到左邊那個參數,Ra它是知道是Rational<int>的,但是看看右邊的參數
int? 不認識,沒有相應函數。
2:所以為了讓編譯器認識它,你必須把這個函式宣告成Rational類的friend函數。這樣編譯器在找到
第一參數的時候,就確定了這個函數處於Rational<int>的類中,然後int類型的6就自然而然地隱式
轉換成Rational<int>類型了。
3:但是這樣還是無法連結,因為連結器只找到了聲明缺不知道定義,因為我們定義的是模版函數,除非你
再實現一個專門針對int類型的operator。但是這樣模版的意義何在?
所以最簡單的辦法就是直接在類內部實現定義式。
4:在類內部實現定義式會造成一個問題:隱式inline,如果這個操作很複雜會造成代碼膨脹,那就只能
選擇調用一個外部函數,因為是inline,所以不會產生效率問題,多棒。
5:來看看具體實現吧 */
template<class T>
const Rational<T> doMultiply(const Rational<T>& r1,const Rational<T>& r2)
{ ...}
template<class T>
Rational
{
...
friend const Rational<T>operator*(const Rational<T>& r1,const Rational<T>& r2)
{ return doMultiply(r1,r2)}
}
// 6:doMultiply無法隱式轉換,但是它不需要這樣的轉換,因為friend函數已經把正確的類型傳入了。
}
//#47 請使用traits classes 表現類型資訊
{
/* c++並不能動態知道一個迭代器的類型,所以我們需要一個巧妙的技巧,那就是traits
比如我想要對單向,雙向,隨機迭代器分別調用一個函數的不同版本,可以藉助iterator_traits: */
template<class Iterator>
void dosomething(Iterator iter)
{ _dosomething(iter,iterator_traits<Iterator>::iterator_category())}
// 這樣就可以藉助傳入的參數來判斷迭代器的類型了。
// 這裡說的很簡略,主要是這東西不是簡單能敘述的,詳細內容可以參考stl源碼剖析。
}
//#48 認識template元編程
{
// 算是一個模版元編程的入門介紹吧,想要瞭解最好看書!!!
}
effective c++ 筆記 (45-48)