A.導(dǎo)讀
泛型編程和面向?qū)ο缶幊屉m然分層不同思維,但是它們正式C++的技術(shù)主線至壤。隨意我們也要討論模版崇渗。
test.cpp
一些書籍:Effective C++ The C++ Standard Library.
標(biāo)準(zhǔn)庫除了去使用他非常方便的京郑,但如果能理解它更好些举,所以有STL源碼解析户魏、標(biāo)準(zhǔn)庫里基本不是面向?qū)ο缶幊痰乃季S叼丑,是泛型編程的思維扛门。用了很多模版论寨,不是用繼承寫的爽茴。同樣的一件事情如果分成很多class的話會(huì)有很多繼承室奏,整個(gè)標(biāo)準(zhǔn)庫的技術(shù)不是用面向?qū)ο蟮乃季S胧沫。C++編譯器酱畅。
B.Conversion Function
轉(zhuǎn)換函數(shù)。
operator double() const{
return (double) (m_numerator/ m_denominator);}
C.non-explicit-one-argument?
explicit-one-argument ctor
Fraction f(3窖逗, 5)
Fraction d2 = f+4//調(diào)用non-explicit ctor將4轉(zhuǎn)為Fraction(4. 1)餐蔬, 然后調(diào)用operatro+
conversion functions vs non-explicit-one-argument ctor
但如果此時(shí)還有operator double()樊诺,第二行會(huì)報(bào)錯(cuò)词爬,ambiguous。
加了explicit后d2 = f+4 4就不會(huì)變成fraction
explicit 百分之九十用在構(gòu)造函數(shù)前面
proxy 用另一種類去代理真正要傳回的值锅锨。轉(zhuǎn)換函數(shù)必搞,有從這邊的轉(zhuǎn)到那邊的恕洲,也有從那邊的轉(zhuǎn)到這邊的霜第,兩個(gè)方向泌类。
D.pointer-like classes關(guān)于智能指針
E.function-like classes
所謂的仿函數(shù)咆课。
他們對操作符()進(jìn)行重載扯俱,至于小括號里面做什么要看設(shè)計(jì)迅栅。
template <class T1, class T2>
struct pair{
T1 first;
T2 second;
? ? pair(): first(T1()), second(T2()) {}
? ? pair(const T1& a, const T2& b)
? ? ? ? : first(a), second(b) {}
}
發(fā)現(xiàn)標(biāo)準(zhǔn)庫中的其他仿函數(shù)都繼承了binary_function和unary_function
這兩個(gè)是仿函數(shù)使用的base classes,所以標(biāo)準(zhǔn)庫里有很多仿函數(shù),他們都重載了()让簿,并繼承了一些奇怪的父類秀睛。
F.namespace經(jīng)驗(yàn)談
把自己的變量和類名等等用自己的namespace包裝起來
int main (int argh, char** argv){
? ? jj01::test_member_template();
? ? j02::test_template_template_param();
}
G.class template類模板
之前已經(jīng)看到過蹂安,模板在類的外面,類內(nèi)要用到的地方都用T來代替畜号。
H.函數(shù)模板
概念完全一樣简软,寫在函數(shù)的前面
template <class T>
inline
const T& min(const T& a, const T& b){
? ? return b<a?b:a;
}
編譯器會(huì)對函數(shù)模板進(jìn)行實(shí)參的推導(dǎo)(argumentt deduction)痹升,所以函數(shù)模板在編譯的時(shí)候并不能確定视卢,當(dāng)被使用的時(shí)候會(huì)再一次確定廊驼。
I.成員模板
成員模板一樣妒挎,聲明放在成員的外面
template<class U1, class U2>
pair(const pair<U1, U2>& p)
:first(p.fist), second(p.second) {}
很多構(gòu)造函數(shù)中會(huì)用到成員模板酝掩。比如在只能指針中
template<typename _Tp>
class shared_ptr:public __shared_ptr <_Tp>{
...
? ? template<typename _Tp1>
? ? explicit shared_ptr(_Tp1* __p)
? ? ? ? :__shared_ptr<_Tp>(__p) {}
...
}
J.模板特化 specialization
特化的反面是泛化期虾,可以理解為當(dāng)我們使用模板的時(shí)候如果出現(xiàn)了在某幾種情況下我們需要進(jìn)行特殊處理時(shí)镶苞,可以進(jìn)行模板特化。
template <class Key>
struct hash {};
template<>
struct hash<int>{
? ? size_t operator() (int x) const {return x;}
}
K.偏特化
分為兩種壕鹉,一種是個(gè)數(shù)上的偏,比如模板參數(shù)有兩個(gè)脊凰,但是在特化的時(shí)候我們只在某一個(gè)值綁定的時(shí)候就要生效茂腥,這個(gè)叫偏特化杈抢,另一種是范圍的偏特化,比如一開始的時(shí)候我們的模板可以允許任何類型仑性,后來我們要把范圍縮小為只允許指針惶楼,這個(gè)叫范圍的偏特化,不要把下面模板中的參數(shù)和上面模板中的混淆诊杆。
L.模板模板參數(shù)
本身是一個(gè)模板參數(shù)歼捐,在模板里面又有模板,關(guān)于typename和class的共通問題晨汹,只有在template<typename T>里面兩個(gè)關(guān)鍵字才共通豹储,模板模板參數(shù)一般用在模板里面需要傳入一個(gè)容器,那容器本身也需要是一個(gè)模板淘这,就會(huì)有兩個(gè)模板的嵌套剥扣。
template<typename T,
? ? ? ? ? ? ? ? template<typename T>?
? ? ? ? ? ? ? ? class Container
? ? ? ? ? ? ? ?>
由于容器傳入其實(shí)不止一個(gè)參數(shù),會(huì)出問題铝穷。
以下不是模板模板參數(shù)
template <class T, class Sequence = deque<T>>
class stack{}
因?yàn)楹笳咭呀?jīng)完全確定了。
M.關(guān)于C++標(biāo)準(zhǔn)庫
最關(guān)鍵的是容器和算法。
接下來是C++2.0的幾個(gè)關(guān)鍵簡單的部分贤姆,variadic template, auto和range-base for loop
N.三個(gè)主題
variadic templates
void print(){}
template<typename T, typename... Types>
void print(const T& firstArg, const Types&... args){
? ? cout <<firstArg<<endl;
? ? print(args...);
}
把輸入的模板和輸入的變量分為一個(gè)和一包,然后利用迭代把所有不同類型的數(shù)據(jù)同時(shí)處理。
如print(7.5, "hello", bites<16>(377), 42)
所以上面一個(gè)print()是必須的,作為一個(gè)迭代循環(huán)的出口碴卧。
如果你想知道后面一包里面有幾個(gè)荧飞,可以使用sizeof...(args)
auto
使用auto的時(shí)候肯定有右邊的等式传睹,作為一個(gè)語法行,不能空定義碧绞。
auto ite = find(c.begin(), c.end(), target);
編譯器會(huì)幫你推院峡。
range-base for
for(dec1: coll) {}
冒號后面一定是一個(gè)容器盹牧,把容器中的每一個(gè)元素設(shè)定為冒號前的變量
vector<double> vec;
for(auto elem:vec){
? ? cout << elem << endl;
}
這樣的寫法比遍歷一個(gè)容器以前的寫法簡單很多,以前要用迭代器的循環(huán)或者foreach
上面這樣的寫法是一個(gè)copy動(dòng)作,不能改變?nèi)萜髦械闹担珎饕每梢愿闹?/p>
for (auto& elem : vec){
? ? elem *=3;
}
O.reference
當(dāng)用引用賦值過后找默,兩個(gè)東西就完全相同了咧欣,只是名字不同蚌父。如
int x = 0;
int*p = &x;
int& r = x;//r代表x,現(xiàn)在r和x都是0
int x2 = 5;
r = x2;//r不能重新代表其他物體,現(xiàn)在r和x都是5
int& r2 = r;
object和其reference大小相同,地址也相同,java中所有的變量都是reference骇窍。
很少聲明一個(gè)變量是reference,一般用在傳參數(shù)中。
void func1(cls* pobj){obj->xxx();}
void func2(cls obj) {obj.xxx();}
void func3(cls& obj) {obj.xxx();}
func1(&obj);//接口不同
func2(obj);
func3(obj);
當(dāng)兩個(gè)函數(shù)的傳參只有reference不一樣時(shí)吁脱,被視為相同的聲明,加了const以后兩個(gè)函數(shù)的簽名被視為不相同。
這次的作業(yè)涉及到了對象在內(nèi)存里是如何存在的废封,讓我學(xué)到了一個(gè)對象中的對齊規(guī)則,在一個(gè)對象中以最長的數(shù)據(jù)類型大小為對齊規(guī)則仇祭,當(dāng)一個(gè)類是虛擬類的時(shí)候颈畸,它會(huì)多一個(gè)虛擬指針用來指向它的虛擬表乌奇。數(shù)據(jù)的順序也會(huì)影響對象的大小眯娱,當(dāng)兩個(gè)數(shù)據(jù)加起來小于等于對齊的大小時(shí)试伙,這兩個(gè)數(shù)據(jù)會(huì)放在連續(xù)位置。當(dāng)子類是多重繼承的時(shí)候,會(huì)有一個(gè)指針指向多個(gè)虛擬指針用來指向多個(gè)虛擬表。另外在使用gdb調(diào)試器的時(shí)候捷雕,也學(xué)會(huì)了很多新的命令使用,比如set p ?pretty on和set p obj on,第一條可以讓結(jié)構(gòu)的顯示按照數(shù)據(jù)類型分段顯示粘驰,后一個(gè)可以顯示對象類型的數(shù)據(jù)屡谐。