程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> [GeekBand] C++ 高級編程技術 (1),geekband高級編程

[GeekBand] C++ 高級編程技術 (1),geekband高級編程

編輯:C++入門知識

[GeekBand] C++ 高級編程技術 (1),geekband高級編程


一、類型轉換

 

 

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;

}

 

        ......

private:

int m_numerator; //

int m_denominator; //

};

    

值得注意的一點是,所有的轉換函數都不需要聲明返回參數類型,也不需要輸入參數。可以通過(double) obj_of_Fraction 進行調用。

除了顯式使用轉換函數以外,轉換函數也會進行隱式調用,例如:

Fraction f(3,5);

double d = 4 + f;

在這種情況下,首先,編譯器會檢查是否存在+運算符的合適的函數重載。如果沒有合適的函數重載被定義,則會先將f隱式轉換為double,再進行相加。

Fraction operator+(const Fraction& f) {

cout << "operator+(): " << f.m_numerator << ' ' << f.m_denominator << endl;

//... plus

return f;

}

那麼,對於d2 = f + 4;有以下兩種路徑,產生了二義性從而不能通過。

為了消除這一二義性,在構造函數前面加了explicit關鍵字。Explicit關鍵字的意義是,這個函數只可以被顯示調用,而不能被任何形式地隱式調用。 (由於這種聲明,Fraction a = 1也不能被調用了。)

如果給拷貝構造函數加explicit關鍵字,則Fraction B(A) 可以使用,Fraction B = A也不能使用了。

 

二、pointer-like class

 

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;

......

}

這裡需要特別說明一下對於->操作符重載的調用,考慮如下代碼:

shared_ptr<Foo> sp(new Foo);

Foo f(*sp);

sp->method();

 

將會自動轉化為px->method();這裡涉及到了'->'的特別行為。'->'運算符的一個特點是,它不會再運算過程中被消耗。'sp->'的運算結果是px,又由於'->'沒有被消掉,因此其轉換為px->method()。

 

2)迭代器——一種特別的智能指針

 

其和智能指針基本一致,只是還需要對++和—運算符進行重載。

T& operator *() const{ return (*node).data; }

T* operator->() const{ return &(operator*();)}

需要注意的一點是,這裡顯式調用了operator*(),這種形式是非常方便的。

三、Function-like class(仿函數)

 

 

即重載()運算符(又名函數調用操作符,其重載時的默認調用位置就在中間),在標准庫中被廣泛使用。

template <class pair>

struct select1st: public uniary_func<.......>{

const typename pair::first_type&

operator()(const pair &x) const{

return x.first;

}

}

 

這樣就能夠像函數一樣使用這個類,select1st(pair(1,2));

四、泛型編程初步

 

 

泛型編程和面向對象編程是C++的兩個重要方面。

  • 類模板和函數模板的作用

     

    通常來講,類模板可以被用來做容器、迭代器等;而函數模板則是被用來做泛型算法。

只需要使用template <class/typename T>進行聲明。

類模板在使用時需要指明參數類型,但函數模板可以自動進行實參推導。

  • 類的成員模板

     

    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) {}

    };

    注意其中的成員函數——拷貝構造函數。通過這種成員模板方式,可以實現拷貝構造。

  • 模板的特化

    模板是一種泛化操作,而特化則是一種逆向的操作,其語法是:

    template<>

    struct hash<int>{

    size_t operator() (int x) const {return x;}

    }

通過這種形式,可以給int參數類型單獨制定方法,同樣的語法也可以使用與函數模板。

cout<<hash<int>()(1000);

其中的hash<int>() 是聲明了一個無參臨時對象。

  • 模板偏特化

4.1個數上的偏特化

 

與全特化類似,這種偏特化也是固定參數進行特化。

泛化聲明:

template<class T1,class T2>

class vector

{......}

 

偏特化聲明:

template<class T2>

class vector <bool,T2>

{......}

 

注意偏特化聲明中的T2雖然仍寫為T2,但與全泛化的T2並沒有關系。

4.2范圍上的偏特化

 

這種偏特化是指對於 const * p類型、*p類型、p類型的限制,偏特化就是按照范圍劃分不同的方法,例如如下的代碼:

template <class T>

class C{......}

 

template <class T>

class C<T*>{......}

 

當僅有第一種定義時,會自動調用第一種類型的模板;然而當有上兩種定義時,對於指針類型的模板參數,可以使用特別的方法定義,這種分類是十分必要的。

  • 模板模板參數

 

template<typename T,

template <typename T>

class Container

>

class XCls

{

private:

Container<T> c;

public:

XCls()

{

for(long i=0; i< 100; ++i)

c.insert(c.end(), T());

}

};

 

注意第二個模板參數template <typename T> class SmartPtr ,其本身又是一個模板。

使用方法:

template <class T>

using Lst = list<T, allocator<T>>;

XCls<string, Lst> mylist;

 

注意:下面的用法不是模板模板參數。

template< class T ,class Sequence = deque<T>>

class stack{

protected:

Sequence C;

}

其中第二個參數制定了stack要依靠什麼基本容器類型進行重載,其具有默認值deque。

使用方式為: stack<int,list<int>> s2; 這裡的list已經不是模板了,它在具體化之前已經變成了普通的模板參數。

  • 數量不定的模板參數(Since C++ 11,使用包)

     

    void print(){}

    template< typename T , typename... Types >

    void print(const T& firstArg,const Types &... args){

    cout<<firstArg<<endl;

    print(args...);

    }

     

…是C++11中的新類型,…代表包(package),也就是以容器存儲的數量不定的參數。對於這種數量不定的模板參數,始終采取將參數分為一個和一包的辦法,這個包可以作為模板參數,也可以作為函數參數。在print()中,其采用了遞歸調用方法。也可以將第二參數其作為容器使用。

五、C++的兩個常用語法糖

 

變量會在容器中遍歷,直到變量結尾。

e.g.

for(auto i:{1,2,3,4}){

......

}

這種語法搭配引用可以修改容器中的值。

for(auto &elem:vector_obj){

elem *= 3;

}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved