C++類模板的分離編譯
過去很多類模板都是整個類連同實(shí)現(xiàn)都放在一個頭文件里,像STL庫就是遵循這樣的策略來實(shí)現(xiàn)類模板的?,F(xiàn)在的標(biāo)準(zhǔn)正試圖矯正這種局面。
在實(shí)現(xiàn)中又許多函數(shù)模板。這意味著每個函數(shù)都必須包含模板聲明,并且在使用作用域操作符的時候,類的名稱必須通過模板變量來實(shí)例化。
比如一個operator=的代碼:
template <typename Object>
const MemoryCell <Object> &
MemoryCell<Object>::operator=(const MemoryCell<Object> & rhs)
{
if(this != &rhs)
storeValue = rhs.storedValue;
return *this;
}
頭文件內(nèi)容
將聲明和實(shí)現(xiàn)都放在頭文件中,對于類是行不通的,因?yàn)槿绻麕讉€不同的源文件都有處理這個頭文件的包含指令的話,就會出現(xiàn)重復(fù)定義函數(shù)的情況。但是,如果在頭文件里的知識模板而不是真實(shí)的類,就不會有問題。
函數(shù)對象
在一個函數(shù)的編寫中,需要像接受參數(shù)一樣接受比較函數(shù),用該比較函數(shù)來決定兩個對象的大小。
使用這種方法的原因是,將比較的規(guī)則從對象中剝離出來,用一個比較函數(shù)來決定。
一個如傳遞參數(shù)一樣傳遞函數(shù)的巧妙辦法是:定義一個包含零個數(shù)據(jù)和一個成員函數(shù)的類,然后傳遞這個類的實(shí)例。從效果上看就是,通過將其放在對象中實(shí)現(xiàn)了函數(shù)的傳遞,該對象通常稱為函數(shù)對象。
舉例:
findMax函數(shù)獲得第二個形參,該形參為泛型類型。為使findMax模板可以無誤地?cái)U(kuò)展,泛型類型必須含有名為isLessThan的成員函數(shù)。該成員函數(shù)獲得第一個泛型類型的兩個形參,并返回一個bool值。
template <typename T, typename Comparator>
const T & findMax(const vector<T> & arr, Comparator cmp)
{
int maxIndex = 0;
for(int i=1;i<arr.size();i++)
if(cmp.isLessThan(arr[maxIndex],arr[i]))
maxIndex = i;
return arr[maxIndex];
}
class CaseInsensitiveCompare
{
public:
bool isLessThan(const string & lhs, const string & rhs) const
{
return stricmp(lhs.c_str(), rhs.c_str()) < 0;
}
};
int main()
{
vector<string> arr(3);
arr[0] = "ZERbad";
arr[1] = "alligator";
arr[2] = "crocodile";
cout << findMax(arr, CaseInsensitiveCompare()) << endl;
return 0;
}
智能指針
包含指針的類需要特別注意復(fù)制控制,原因是復(fù)制指針時只復(fù)制指針的地址,而不會復(fù)制指針指向的對象。
當(dāng)類中有指針成員時,一般有兩種方式來管理指針成員:一是采用值型的方式管理,每個類對象都保留一份指針指向的對象的拷貝;另一種更優(yōu)雅的方式是使用智能指針,從而實(shí)現(xiàn)指針指向的對象的共享。
智能指針(smart pointer)的一種通用實(shí)現(xiàn)技術(shù)是使用引用計(jì)數(shù)(reference count)。智能指針類將一個計(jì)數(shù)器與類指向的對象相關(guān)聯(lián),引用計(jì)數(shù)跟蹤該類有多少個對象的指針指向同一對象。
管理指針成員
設(shè)計(jì)具有指針成員的類時,類的設(shè)計(jì)者必須首先需要決定的是該指針應(yīng)提供什么行為。將一個指針復(fù)制到另一個指針時,兩個指針指向同一對象。當(dāng)兩個指針指向同一對象時,可能使用任一指針改變基礎(chǔ)對象。類似地,很可能一個指針刪除了一個對象時,另一指針的用戶還認(rèn)為基礎(chǔ)對象仍然存在。
大多數(shù)C++類采用以下三種方法之一管理指針成員:
- 指針成員采用常規(guī)指針型行為。這樣的類具有指針的所有缺陷但無需特殊的復(fù)制控制。
- 類可以實(shí)現(xiàn)所謂的“智能指針”行為。指針?biāo)赶虻膶ο髸r共享的,但類能夠防止懸垂指針。
- 類采用值型行為。指針?biāo)赶虻膶ο髸r唯一的,由每個類對象獨(dú)立管理。
懸垂指針
具有指針成員且使用默認(rèn)合成復(fù)制構(gòu)造函數(shù)的類,因?yàn)轭惖膹?fù)制時,直接復(fù)制指針。用戶必須保證只要類對象存在,該指針指向的對象就存在。如果之前指向的對象不再存在了,此類指針稱為懸垂指針。結(jié)果未定義,往往導(dǎo)致程序錯誤,難以檢測。我們可以引入智能指針來防止懸垂指針的出現(xiàn)。
關(guān)于智能指針的具體內(nèi)容請移步智能指針類和OpenCV的Ptr模板類
non-const成員函數(shù)調(diào)用const成員函數(shù)
在operator[]函數(shù)的編寫中,我們要做的其實(shí)是實(shí)現(xiàn)其機(jī)能一次,并使用它兩次。
你必須令其中一個調(diào)用另一個。這促使我們將常量性轉(zhuǎn)除。
當(dāng)const operator[]完全做了non-const版本該做的一切時,如果將返回值的const轉(zhuǎn)除是安全的,因?yàn)椴徽撜l調(diào)用non-const operator[]都一定有個non-const對象,否則就不能調(diào)用non-const函數(shù)。所以令non-const operator調(diào)用其const函數(shù)式一個避免代碼重復(fù)的安全做法。
class A{
public:
const char& operator[](std::size_t position) const
{
...
...
return text[position];
}
char& operator[](std::size_t position)
{
return
const_cast<char &>(
static_cast<const A&>(*this)[position]
);
}
private:
std::string text;
}
要讓non-const operator[]調(diào)用const operator[],但non-const operator[]內(nèi)部如果只是單純調(diào)用operator[],會遞歸調(diào)用自己。所以我們必須明確指出調(diào)用的是const operator[]。這里將*this從原始類型A&轉(zhuǎn)型為const A&。這樣為 *this 添加const。這里我們使用static_cast進(jìn)行安全轉(zhuǎn)型。
第二次則是從const operator[]的返回值中移除const。這里只能借助const_cast完成。
如果在const函數(shù)內(nèi)調(diào)用non-const函數(shù),就會改變對象的邏輯狀態(tài),所以const成員函數(shù)調(diào)用non-const成員函數(shù)是一種錯誤行為;而non-const成員函數(shù)本來就可以對其對象做任何動作,所以在其中調(diào)用一個const成員函數(shù)并不會帶來風(fēng)險。
轉(zhuǎn)載請注明作者Jason Ding及其出處
Github博客主頁(http://jasonding1354.github.io/)
CSDN博客(http://blog.csdn.net/jasonding1354)
簡書主頁(http://www.itdecent.cn/users/2bd9b48f6ea8/latest_articles)
百度搜索jasonding1354進(jìn)入我的博客主頁