(給CPP開發者加星標,提升C/C++技能)
blog.csdn.net/l2563898960/article/details/97769569【導讀】:如何防止C++構造函數的隱式轉換,explicit關鍵字可以幫助我們解決問題。以下是正文
explicit關鍵字的作用explicit關鍵字在寫程序時使用的次數較少,但是仔細觀察會發現,在C++標準庫中的相關類聲明中explicit出現的頻率是很高的,那麼explicit關鍵字到底有什麼作用呢?接下來我就為大家一一解答。
explicit為清晰的;明確的之意.顧名思義,關鍵字explicit可以阻止隱式轉換的發生。
例如: C++中只帶有一個參數的構造函數,或者或者除了第一個參數外其餘參數都有預設值的多參構造函數,承擔了兩個角色:
1.用於構建單參數的類對象。
2.隱含的類型轉換操作符。
例如:一個類A的構造函數A(int i)就是,既可以用來作為構造器,又可以實現隱式轉換A a=1;因為1可以通過構造函數A(int i)轉換為一個類A的對象。(隱含的類型轉換操作符)
但有時我們並不想讓他進行隱式類型轉換,這時C++的explicit關鍵字就起到作用了。
注意:當類的聲明和定義分別在兩個文件中時,explicit只能寫在在聲明中,不能寫在定義中。
下面我將為大家介紹三種使用explicit關鍵字的情況:
#include<iostream>using namespace std;class Fraction{public: Fraction(int numerator, int denominator = 1): m_numerator(numerator), m_denominator(denominator){} operator double() const{ return (double)m_numerator/m_denominator; }private: int m_numerator; int m_denominator;}
int main(void){ Fraction fraction(3, 5); double d = 3.5 + f; cout << d << endl; return 0;}我們設計了一個Fraction類(分數類), 在主函數中定義了一個分數對象f,然後將3.5 + f賦值給double類型變量d, 但是我們發現f並不是一個double類型的變量,因此編譯器會從Fraction類中尋找operator double()函數,隱式調用該函數將Fraction類型轉換成一個double類型. operator double()就是我們所說的類型轉換函數(type conversion function)。
類型轉換函數的一般形式
1.轉換函數必須是類的成員函數
2.轉換函數不能聲明返回類型
3.形參列表必須為空
4.類型轉換函數通常應該是const當我們想要在明確聲明類型轉換的時候,才使用類型轉化函數時,這時我們就需要使用到explicit關鍵字了.使用方法如下:
#include<iostream>using namespace std;class Fraction{public: Fraction(int numerator, int denominator = 1): m_numerator(numerator), m_denominator(denominator){} explicit operator double() const{ return (double)m_numerator/m_denominator; }private: int m_numerator; int m_denominator;}
int main(void){ Fraction fraction(3, 5); double d = 3.5 + static_cast<double>(f); cout << d << endl; return 0;}注意,這時當我們想調用類型轉換函數的時候,需要寫成static_cast<double>(f);
注意static_cast 是C++11 引入的類型轉換運算符。
單操作數構造函數還是採用上面的Fraction類,這次我們重載(overload) 「+」 號運算符,使得仍然可以達到相同的效果。
#include<iostream>using namespace stdclass Fraction{ public: Fraction(int numerator, int denominator = 1): m_numerator(numerator), m_denominator(denominator){} double operator+(const Fraction& a) { return (a.m_numerator + this->m_numerator)/(a.denominator + this->m_denominator); } private: int m_numerator; int m_denominator; } int main(void){ Fraction fraction(3, 5); double d = f + 3; cout << d << endl; return 0;}在double d = f + 3 這句話中構造函數就是前面所提到的第二種角色隱含的類型轉換操作符。因為執行到這句話首先會調用+的重載函數,該函數的調用對象默認為左操作數,右操作數為Fraction類型,因此會調用構造函數將3轉換成Fraction類型,然後將得到的返回值double類型賦值給變量d。
同理如果不想讓構造函數進行隱式類型轉換,可以在構造函數前面加上explicit關鍵字,防止進行隱式轉換.使用方法如下:#include<iostream>using namespace stdclass Fraction{ public: explicit Fraction(int numerator, int denominator = 1): m_numerator(numerator), m_denominator(denominator){} double operator+(const Fraction& a) { return (a.m_numerator + this->m_numerator)/(a.denominator + this->m_denominator); } private: int m_numerator; int m_denominator; } int main(void){ Fraction fraction(3, 5); double d = f + 3; cout << d << endl; return 0;}你可能會注意到,加上explicit 關鍵字之後,這個代碼將不能正確執行。
同時出現拷貝構造函數和類型轉換函數我們看如下一段代碼:
#include<iostream>using namespace stdclass Fraction{ public: Fraction(int numerator, int denominator = 1): m_numerator(numerator), m_denominator(denominator){} operator int(){ return m_numerator/denominator; } int operator+(const Fraction& a) { return (a.m_numerator + this->m_numerator)/(a.denominator + this->m_denominator); } private: int m_numerator; int m_denominator; } int main(void){ Fraction fraction(3, 5); int d = f + 3; cout << d << endl; return 0;}這時你會發現會產生一個二義性問題,在執行int d = f + 3的時候到底是該選擇類型轉換函數,將f轉換成int類型再繼續運算呢?還是應該將3作為構造函數的參數進行隱式轉換,然後再調用+運算符重載函數呢?
解決這個問題的辦法就是使用explicit關鍵字限制,具體方法有兩種:
1.在構造函數前面加上explicit關鍵字, 防止int類型隱式轉換成為Fraction類型。拷貝構造函數
2.在類型轉換函數前面加上explicit關鍵字,這樣只有顯示調用類型轉換static_cast<int>(f)時,才會調用該函數。Copy constructor也是同樣的,如果Copy constructor被聲明為explicit,則這個類對象不能隱式調用,用於傳參傳遞和函數返回值。
Complex<double> v1(1.2, 2.3); Complex<double> v2 = v1;
void func(Complex<double> v); func(v1);
Complex<double> func() { Complex<double> v1(2.3, 1.2); return v1; } 總結C++中,一個參數的構造函數(或者除了第一個參數外其餘參數都有預設值的多參構造函數),承擔了兩個角色。
用於構建單參數的類對象。
隱含的類型轉換操作符。
explicit關鍵字只對有一個參數的類構造函數有效, 如果類構造函數參數大於或等於兩個時, 是不會產生隱式轉換的, 所以explicit關鍵字也就無效了。
聲明為explicit的構造函數不能在隱式轉換中使用,只能顯示調用,去構造一個類對象。
Base base(『a』) Base base = 『a』儘量避免有二義性的類型轉換,如果類中包含一個或多個隱式類型轉換,則必需使用explicit關鍵字確保在類類型和目標類型之間只存在唯一一種隱式轉換方式,否則將出現二義性。
但是將拷貝構造函數聲明成explicit並不是良好的設計,一般只將有單個參數的constructor聲明為explicit,而copy constructor不要聲明為explicit。
- EOF -
關於 C++ 中explicit關鍵字詳解,歡迎在評論中和我探討。覺得文章不錯,請點讚和在看支持我繼續分享好文。謝謝!
關注『CPP開發者』
看精選C++技術文章 . 加C++開發者專屬圈子
↓↓↓
點讚和在看就是最大的支持❤️