淺談c++之面向對象程序設計的幾種小技巧系列之第一部分--(boolan)

  既然說是淺談C++之面向程序設計,那麼本次我會和大家分享面向對象設計中經常使用的幾種類型:1.conversion function(轉換函數)、2.non-explicit-one-argument-ctor、3.explicit-one-argument-ctor、4.pointer-like class(智能指針)、5.Function-like class(仿函數)、6.namespace(命名空間)、7.class template(類模板)、8.Function template(函數模板)、9.member template(成員模板)、10.specialization(模板特化)、11.partial specialization(模板偏特化)、12.template template parameter (模板模板參數)、13.關於C++標準庫、14.variadic template(since C++11)、15.reference、16.複合&繼承關係下的構造函數和析構函數。


  下面對上述列出的C++小技巧進行展開說明:


  注:本次文章將前3中小技巧作爲本次《淺談C++之面向對象程序設計的幾種小技巧》系列的第一部分進行說明,對於剩下的其他十三種小技巧請參照《淺談C++之面向對象程序設計的幾種小技巧》系列的後續的文章。謝謝!


  • * 1.conversion function (轉換函數):*

  我們知道class(類)是C++中重要的一個機制,對於我所說的轉換函數,在C++中往往有兩種形式,一種是將:class(類)轉出去;另一種是將外界的東西轉化成class(類)。對於我說的這兩種大家可能不是太明白,下面結合程序做進一步的說明:

#include<iostream>
using namespace std;
//如下:將class轉出去,通過利用operator將class(類)原本的類型轉化成另一種類型
class Fraction{
public:
    Fraction(int num, int den = 1) :
        m_num(num), m_den(den){}
    operator double()const{   //將數據類型爲的 Fraction 的數據轉化成 double 類型數據
        return static_cast<double>(m_num)/ static_cast<double>(m_den);
    }
private:
    int m_num;
    int m_den;
};
int main()
{
    Fraction f(3, 5);//對象f
    double d = 3+f;//編譯器將自動將對象f轉化成double型
    return 0;
}

  上述類Fraction之所以會轉化成double類型,是因爲在類Fraction中編譯器自動自動調用類Fraction中的轉化函數operator double() const{}實現函數轉化(將class轉出去)。


  對於重載函數(轉化函數)operator double() const{},其中double()表示Fraction類轉化後的類型(轉化後爲double型),小括號裏面無參數;返回類型不需要要寫(因爲在轉化前並不知道會將其轉化成什麼類型,如果貿然寫上返回類型,容易在寫返回類型時將類型寫錯,從而造成編譯的錯誤,那麼幹脆不寫,因爲返回類型就是轉化後的類型。


  同時大家可能會注意到,重載函數(轉化函數)中的const,之所以在函數後面加const是因爲該函數體在執行的過程中不會改變函數體中的參數值。也就是說在類中被const聲明的成員函數不可以修改對象的數據,不管對象是否具有const性質.它在編譯時,以是否修改成員數據爲依據,進行檢查.所以加上const。那麼有的人可能會問,如果不加可不可以。我的回答是可以,但是最好加上,而且對於有些程序來說,不加const的話有可能會造成不可預知的程序錯誤。類中的const成員函數的目的是爲了指明哪個成員函數可以在const對象上被調用。


  通過上述我們知道了函數轉化的一種方法:將class轉出去。如果寫的時候認爲合理的話,可以給類寫好幾個轉化函數。剛纔說了,對於轉化函數有兩種,上述只是介紹了其中的一種,並且我們平時說的轉化函數也往往就是指這一種,而另一種轉化函數——將別的東西轉化成這種類(class)就是下面要給大家介紹的non-explicit-one-argument-ctor。


  • * 2.non-explicit-one-argument-ctor:*

  通過名字可以知道,這是一種只有的一個實參的構造函數,並且構造函數前面不加explicit。


  對於C++中的構造函數前面加關鍵字explicit,可以阻止不應該允許的經過轉換構造函數進行的隱式轉換的發生,說明構造器只能被明確的調用。申明爲explicit的Ctor(構造函數)不能在隱式轉換中使用。C++中,一個參數的構造函數,承擔了兩個角色。a.構造函數;b.是個默認且隱含的類型轉換操作符。


  介紹完explicit的作用後,我們言歸正傳繼續介紹non-explicit-one-argument-cotr這種類型的轉化(將外界其他類型的東西轉化成class(類)的類型。同樣我們還是通過一段程序來進行說明。

#include<iostream>
using namespace std;
//如下:將class轉出去,通過利用operator將class(類)原本的類型轉化成另一種類型
class Fraction{
public:
    Fraction(int num, int den = 1) :
        m_num(num), m_den(den){}//此構造函數有一個實參den=1
     Fraction  operator + (const Fraction & f){   //將數據類型爲的 Fraction 的數據轉化成 double 類型數據
        return Fraction((this->m_num)+(f.m_num)*(this->m_den),this->m_den);
    }
     int getNum()const{ return m_num; }
     int getDen()const{ return m_den; }
private:
    int m_num;
    int m_den;
};
int main()
{
    Fraction f(3, 5);
    Fraction d = f+3;
    cout << "(" << d.getNum() << "," << d.getDen() << ")"<<endl;
    return 0;
}

  上述程序的輸出結果爲:d=(18,5)


  從上述的程序可以看出,這是一種隱式轉換,將 Fraction d = f+3;中的3通過構造函數進行隱式轉化成(3,1)其類型爲 Fraction 類型。再通過運算符(“+”)進行重載,完成 Fraction 類的對象相加的操作。


  通過上述程序,相信已經可以窺探到:non-explicit-one-argument-cotr  的奧義了。同時也會知道explicit關鍵字在構造函數中的作用。爲了加深對explicit這個關鍵字的理解,下面我們在構造函數的前面加上explicit進行比對,也就是我接下來要說的explicit-one-argument-ctor……


  • 3.explicit-one-argument-ctor:

  對於將class(類)轉出去[即所說的conversion function (轉換函數)],以及將外界其他類型的東西轉化成class(類)的類型[即所說的non-explicit-one-argument-ctor]。那麼如果給ctor(構造函數)加上explicit後會如何呢。


  下面我們介紹在ctor(構造函數)前面加上關鍵字explicit後會如何,通過關鍵字的名字————explicit可以知道,加上這個關鍵字之後,構造函數將只能通過顯式調用,而不能像上面我麼你說的第二種情況進行隱式調用。


  爲了將其說的更清晰,還是選擇通過一段程序來進行講解。

#include<iostream>
using namespace std;
//如下:將class轉出去,通過利用operator將class(類)原本的類型轉化成另一種類型
class Fraction{
public:
    explicit Fraction(int num, int den = 1) ://將構造函數前面加上關鍵字explicit後,該構造函數將變成只能通過顯示調用。
        m_num(num), m_den(den){}
    operator double()const{   //將數據類型爲的 Fraction 的數據轉化成 double 類型數據
        return static_cast<double>(m_num) / static_cast<double>(m_den);
    }
    Fraction  operator + (const Fraction & f){   //將數據類型爲的 Fraction 的數據轉化成 double 類型數據
        return Fraction((this->m_num) + (f.m_num)*(this->m_den), this->m_den);
    }
private:
    int m_num;
    int m_den;
};
int main()
{
    Fraction f(3, 5);
    Fraction d1 = f + 4; //Error C2440:"初始化“:無法從”double“轉換爲Fraction”
    double d = 3 + f;
    cout << d << endl;
    return 0;
}

  上面的這段程序編譯時將會出現錯誤,且它的錯誤提示爲    Error C2440:”初始化“:無法從”double“轉換爲Fraction”。這時候需要思考程序爲什麼會出現這種錯誤的提示:因爲在構造函數的前面加上了explicit,使構造函數:

explicit Fraction(int num, int den = 1) :
        m_num(num), m_den(den){}

  只能通過顯式進行調用,而不能進行隱式調用(即不能夠通過構造函數將數字“4”轉換成Fraction(4,1),也就是說當構造函數前面加上了關鍵字explicit後,這種隱式的轉化是不被允許的。


  以上部分就是本次文章《淺談C++之面向對象程序設計的幾種小技巧》的第一部分的全部內容,對於其他的三種小技巧,請見《淺談C++之面向對象程序設計的幾種小技巧》系類的後續文章。謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章