1.轉(zhuǎn)換函數(shù)
class Fraction
{
public:
explicit Fraction(int num, int den=1)
: m_numerator(num), m_denominator(den)
{ cout << m_numerator << ' ' << m_denominator << endl; }
operator double() const {
return (double)m_numerator / m_denominator;
}
Fraction operator+(const Fraction& f) {
cout << "operator+(): " << f.m_numerator << ' ' << f.m_denominator << endl;
//... plus
return f;
}
標(biāo)黃的即為轉(zhuǎn)換函數(shù),函數(shù)名稱為要轉(zhuǎn)換的類型,無參數(shù)無返回值,且不改變成員數(shù)據(jù),所以用const修飾函數(shù)
double d = 4 + f,編譯器首先查找是否重載操作符+,若沒有則看f是否有轉(zhuǎn)換函數(shù),若有則可以編譯通過
2.non-explicit-one-argument ctor
藍(lán)色段表示一個(gè)實(shí)參就夠了,因?yàn)榈诙€(gè)實(shí)參有默認(rèn)值
Fraction d2 = f+4; 調(diào)用non-explicit ctor 將4轉(zhuǎn)為Fraction,然后調(diào)用operator+
如果non-explicit-one-argument ctor與轉(zhuǎn)換函數(shù)并存時(shí),F(xiàn)raction d2=f+4;會(huì)出錯(cuò),會(huì)造成編譯器困惑,可以是Fraction與Fraction相加,也可以是Double與Double相加,因此要保證唯一性,不能有二義性。
在構(gòu)造函數(shù)前加explicit,則無法將double轉(zhuǎn)換為Fraction,一般只在構(gòu)造函數(shù)前用
3 pointer-like classes
3.1 智能指針
template<class T>
class shared_ptr
{
public:
T& operator*() const
{ return *px; }
T* operator->() const
{ return px;}
shared_ptr(T* p) : px(p) { }
private:
T* px;
long* pn;
}
這種類要有指針的基本功能,首先可以用普通指針來初始化,其次要重載操作符* 和 ->
->有個(gè)特殊的地方,->用掉之后還會(huì)繼續(xù)作用下去,所以sp->method(); 可以寫成px->method();
3.2迭代器
主要用途是遍歷容器,迭代器也是pointer-like classes,需要額外重載很多操作符,比如++、--等
reference operator*() const
{ return (*node).data; }
pointer operator->() const
{ return &(operator*()); }
//->的重載中調(diào)用操作符*的重載
//即return的是&((*node).data)
使用示例
list<Foo>::iterator ite;
...
*ite;// 獲取一個(gè)Foo對(duì)象
ite->method();
//意思是調(diào)用Foo::method
//相當(dāng)于(*ite).method
//相當(dāng)于(&(*ite))->method
4.funtion-like classes,所謂仿函數(shù)
能夠接受()的東西則稱之為函數(shù),或者像函數(shù)的類
template<class T>
struct identity :public unary_function<T,T> {
const T&;
operator() (const T& x) const { return x; }
}
function-like classes 都重載了()操作符,都會(huì)繼承奇特的base classes,unary_funtion 和 binary_function
5.模板
5.1 類模板
template<typename T>
class complex
{
public:
complex (T r = 0, T i = 0)
: re(r),im(i) { }
private:
T re, im;
}
使用方法
complex<double> c1(2.5,1.5);
complex<int> c2(2,6);
5.2 函數(shù)模板
template <class T>
inline
const T& min(const T& a, const T& b)
{
return b < a? b : a;
}
編譯器會(huì)對(duì)function template進(jìn)行實(shí)參推導(dǎo),編譯器無需知道T的具體類型
5.3成員模板
template <class T1, class T2>
struct pair {
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair() : first(T1()), second(T2()) {}
pair(const T1& a, const T2& b) : first(a), second(b) {}
template <class U1, class U2>
pair(const pair<U1, U2>& p) : first(p.first), second(p.second) {}
};
黃色段落即為成員模板,常見于標(biāo)準(zhǔn)庫中類的構(gòu)造函數(shù),為的是讓構(gòu)造函數(shù)更有彈性
5.4 specialization 模板特化
面對(duì)某些獨(dú)特的類型要做特殊的設(shè)計(jì)時(shí)需要用到模板特化
模板泛化
template <class Key>
struct hash { };
這種情況下,key可以是任意的class類型,因此稱之為泛化
模板特化
template<>
struct hash<char>{
size_t operator() (char x) const {return x;}
};
如果<>中不是char,則調(diào)用泛化,若類型為特化中的已經(jīng)指定的類型,則調(diào)用特化的內(nèi)容
5.5.模板偏特化
偏特化就是如果這個(gè)模板有多個(gè)類型,那么只限定其中的一部分。包括個(gè)數(shù)上的偏以及范圍上的偏
個(gè)數(shù)上的偏
template<typename T, typaname Alloc=.......>
class vector
{
...
}
template<typename Alloc=......>
class vector<bool,Alloc>
可以綁定不定個(gè)數(shù)的模板
范圍的偏
template <typename T>
class C
{
...
};
template<typename T>
class C<T*>
{
...
}
上述即為范圍的偏,從任意范圍縮小為必須是指針,但指針可以指向任意類型
5.6 模板模板參數(shù)
template<typename T,
template <typename T>
class Container>
>
第二個(gè)參數(shù)為模板參數(shù)
5.7 c++11的三個(gè)主題
5.7.1 variadic templates 數(shù)量不定的模板參數(shù)
允許寫任意個(gè)數(shù)的模板
template<typename T,typename... Types>
void print(const T& firstArg,const Types&... args)
{
cout<<firstArg<<endl;
print(args...);
}
接受兩組參數(shù),第一組firstArg,第二組為args數(shù)量不定,分為一個(gè)和一包(用...表示)
...就是一個(gè)所謂的pack(包)
用于template parameters,就是template parameters pack(模板參數(shù)包)
用于function parameter types,就是function parameter types pack(函數(shù)參數(shù)類型包)
用于function parameters,就是function parameters pack(函數(shù)參數(shù)包)
5.7.2 auto
list<string> c;
...
list<string>::iterator ite;
ite = find(c.begin(),c.end(),target);
可改為
list<string> c;
...
auto ite = find(c.begin(),c.end(),target);
auto為編譯器自動(dòng)推導(dǎo)類型
錯(cuò)誤用法
list<string> c;
...
auto ite;
ite = find(c.begin(),c.end(),target);
該寫法編譯器無法推導(dǎo)ite的類型,聲明對(duì)象時(shí)未賦值,無法推導(dǎo)其類型
5.7.3ranged-base for
for(dec1:col1){
statement
}
編譯器會(huì)找出容易col1中的每個(gè)元素,復(fù)制到dec1中,達(dá)到遍歷容器的效果
for(int i : {2, 3, 4, 5, 6 })
{
cout<<i<<endl;
}
vector<double> vec;
...
for( auto elem : vec){
cout<<elem<<endl;
}//pass by value
for( auto& elem : vec){
elem *= 3;
}
//pass by reference,對(duì)vector本身進(jìn)行操作,而不是副本
5.8 reference
三種變量 value pointer reference
int x = 0;
int* p = &r;
int& r = x; //r代表x,現(xiàn)在r,x都是0
int x2 = 5;
r = x2; //r不能重新代表其他物體,現(xiàn)在r,x都是5
int r2 = r;// 現(xiàn)在r2是5(r2代表r,亦相當(dāng)于代表x)
聲明一個(gè)reference時(shí),一定要有初始值,reference一旦聲明后就不能再代表其他變量
reference的常見用途
a.用于參數(shù)傳遞,pass by reference
b.用于返回值,return by reference
通常不用于聲明變量
double imag(const double& im) {}
double imag(const double im){}
函數(shù)簽名相同,無法共存
const是函數(shù)簽名的一部分,加了const即算重載