【GeekBand】 C++面向?qū)ο蟾呒?jí)編程(下) 首周

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即算重載

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容