1.non-explicit-one-argument ctor
one-argument的意思就是,只要一個實參就夠了,但是你要給兩個也行。
代碼例子:
class Fraction
{
public:
Fraction(int num, int den=1)
: m_numerator(num),m_denominator(den){}
Fraction operator+(const Fraction& f){ return Fraction(....); }
private:
int m_numerator;
int m_denominator;
};
測試用例:
Fraction f(3,5);
Fraction d2 = f + 4;
當第二個語句使用f+4的時候,編譯器會自動去尋找是否有operator+這個函數,找到了我們發現,這條語句:Fraction operator+(const Fraction& f){ return Fraction(....); }
+號左邊十個Fraction,右邊也是Fraction,設計成分數+分數。但是實際上卻是f+4,那麼編譯器就會去考慮4是否
能夠轉換成Fraction。編譯器發現這個語句:
Fraction(int num, int den=1)
: m_numerator(num),m_denominator(den){}
那麼4就轉換成了4/1,那麼語句f+4就通過了編譯器。
整個過程就是先調用non-explicit ctor轉換爲Fraction,然後調用operator+。
2.但是假如與之前的operator double()並存的話。
代碼:
class Fraction
{
public :
Fraction (int num, int den=1)
:m_numerator(num),m_denominator(den){}
operator double() const{ return (double)( m_numerator/m_denominator);}
Fraction operator+(const Fraction& f){ return Fraction(......); }
private:
int m_numerator;
int m_denominator;
};
測試用例:
Fraction f(3,5);
Fraction d2=f+4; //[Error] ambiguous
這樣看起來,先將4轉換成4/1,與f相加得到一個Fraction,看似行得通。
但是看operator double(),將f轉換爲0.6,加上4得到4.6,那麼4.6是否能轉換爲Fraction?
這樣的話,編譯器就會引起歧義,就會報錯。
當然,這個代碼引起的問題和之前的轉換函數的筆記中的代碼是一樣的,但是在上一個筆記中使用者使用的是
double d=f+4;
所以得出結論,類內的設計以及是否會出現歧義,需要更多地去考慮使用者是如何使用的。
3.explicit-one-argument ctor
這個的explicit的意思是明白的明確的,這告訴編譯器來,我這就是個明確的構造函數,你不能讓4編程4/1,只能用來當作構造函數。
代碼:
class Fraction
{
public :
explict Fraction (int num, int den=1)
:m_numerator(num),m_denominator(den){}
operator double() const{ return (double)( m_numerator/m_denominator);}
Fraction operator+(const Fraction& f){ return Fraction(......); }
private:
int m_numerator;
int m_denominator;
};
測試用例:
Fraction f(3,5);
Fraction d2=f+4; //[Error]
這個時候這個加法就是失敗的,因爲找到operator+的時候,4無法轉換爲4/1,因爲explict,所以4無法轉換,所以報錯
這個explict百分90都用在構造函數,另外就使用在模板的一個很小的部分。
4.回到轉換函數,標準庫中使用到的轉換函數。
代碼例子:
template <class Alloc>
class vector<bool,Alloc>
{
public:
typedef __bit_reference reference;
pretected:
reference operator[](size_type n) { return *(begin()+difference_type(n)); }
....
};
struct __bit_reference
{
unsigned int* p;
unsigned int mask;
...
public:
operator bool() const { return !(!(*p & mask)) }
...
}
第一段代碼中,vector的語法是模板的偏特化,從裏面有個函數是對[]的重載。
它傳回的是reference,可以看得出,這個代碼傳回的是一個bool值,但是傳回的是reference。
這種設計方式稱爲代理。
那麼拿reference來代表一個bool值,就需要把reference轉換成一個bool,所以在__bit_reference中有一個轉換函數。