1. 程式人生 > >類5(轉換構造函數)

類5(轉換構造函數)

sin string類型 類型 類型轉換 error iostream r+ main 自動轉換

轉換構造函數:

當一個構造函數只有一個參數,而且該參數又不是本類的const引用時,這種構造函數稱為轉換構造函數。

轉換構造函數的作用是將一個其他類型的數據轉換成一個類的對象。註意:轉換構造函數只能有一個參數。如果有多個參數,就不是轉換構造函數:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class Sales_data{
 5     
 6     //數據成員
 7 private:
 8     std::string book_no;
 9     unsigned units_sold = 1;
10     double
revenue = 1.0; 11 12 public: 13 Sales_data() = default;//不接受任何實參,默認構造函數 14 Sales_data(const std::string &s): book_no(s){}//只有一個形參,類型轉換構造函數 15 Sales_data(const std::string &s, unsigned n, double p): book_no(s), units_sold(n), revenue(p * n){} 16 Sales_data(std::istream&); 17 18
Sales_data operator+=(const Sales_data &it){ 19 book_no += it.book_no; 20 units_sold += it.units_sold; 21 revenue += it.revenue; 22 return *this; 23 } 24 25 void out_put(std::ostream &os){ 26 os << book_no << " " << units_sold << "
" << revenue << std::endl; 27 } 28 29 Sales_data& combine(const Sales_data&); 30 }; 31 32 Sales_data& Sales_data::combine(const Sales_data &rhs){ 33 book_no += rhs.book_no; 34 units_sold += rhs.units_sold; 35 revenue += rhs.revenue; 36 return *this; 37 } 38 39 // Sales_data operator+(const Sales_data &it1, const Sales_data &it2); 40 41 int main(void){ 42 Sales_data("jfl");//構造一個臨時Sales_data對象 43 Sales_data cnt("hello"); 44 string null_book = " world"; 45 cnt.combine(null_book);//null_book被自動轉換成Sales_data對象並綁定到引用變量rhs上, 46 // 構造出的臨時Sales_data對象中book_no值為null_book,units為1,revenue為1.0 47 // cnt.combine(" world");//需要進行兩步類型轉換,error(" world"要先轉換為string類型,然後再轉換成Sales_data類型) 48 cnt.out_put(cout);//輸出hello world 2 2 49 cnt += null_book;//同上,null_book被自動轉換成Sales_data對象 50 cnt.out_put(cout);//輸出hello world world 3 3 51 return 0; 52 }

還需要註意的是:編譯器只會自動地執行以步類型轉換。所以在上例中 cnt.combine("world");和 cnt += "world");都是錯誤的,因為其隱式的使用了兩種轉換規則,先把 "world" 轉換成 string,再把這個臨時 string 變量轉換成 Sales_data。要使上面調用變成正確的,我們可以先將 "world" 顯示的轉換成 string 或者 Sales_data:

1     cnt.combine(string("world"));
2     cnt.combine(Sales_data("world"));
3     cnt += string("world");
4     cnt += Sales_data("world");

類型轉換函數不總是有效:

是否需要從 string 到 Sales_data 的轉換依賴於我們對用戶使用該轉換的看法。在上面的例子中,這種轉換可能是對的。 null_book 中的 string 可能表示了一個不存在的 isbn 編號。

但是如果將一個 istream 對象 cin 轉換為 Sales_data 的話,顯然不是我們想要的結果:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class Sales_data{
 5 friend std::istream &read(std::istream&, Sales_data&);
 6     
 7     //數據成員
 8 private:
 9     std::string book_no;
10     unsigned units_sold = 1;
11     double revenue = 1.0;
12 
13 public:
14     Sales_data() = default;//不接受任何實參,默認構造函數
15     Sales_data(const std::string &s): book_no(s){}//只有一個形參,類型轉換構造函數
16     Sales_data(const std::string &s, unsigned n, double p): book_no(s), units_sold(n), revenue(p * n){}
17     Sales_data(std::istream&);//只有一個形參,類型轉換構造函數
18 
19     void out_put(std::ostream &os){
20         os << book_no << " " << units_sold << " " << revenue << std::endl;
21     }
22 
23     Sales_data& combine(const Sales_data&);
24 };
25 
26 Sales_data& Sales_data::combine(const Sales_data &rhs){
27     book_no += rhs.book_no;
28     units_sold += rhs.units_sold;
29     revenue += rhs.revenue;
30     return *this;
31 }
32 
33 std::istream &read(std::istream&, Sales_data&);
34 
35 Sales_data::Sales_data(std::istream &is){
36     read(is, *this);
37 }
38 
39 istream &read(istream &is, Sales_data &item){
40     double price = 0;
41     is >> item.book_no >> item.units_sold >> price;
42     item.revenue = price * item.units_sold;
43     return is;
44 }
45 
46 int main(void){
47     Sales_data cnt("hello");
48     cnt.combine(cin);
49     cnt.out_put(cout);
50     return 0;
51 }

技術分享圖片

cnt.combine(cin);先執行轉換構造函數

Sales_data::Sales_data(std::istream &is)

將 cin 轉換成 Sales_data 類型,因為該函數體中又調用了 read 函數,所以會產生輸入。構造的臨時 Sales_data 對象的初始化數據由輸入數據產生。因此最終輸出:helloworld 2 2

抑制構造函數定義的隱式轉換:

我們可以通過將構造函數聲明為 explicit 阻止構造轉換函數的隱式轉換:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class Sales_data{
 5 friend std::istream &read(std::istream&, Sales_data&);
 6     
 7     //數據成員
 8 private:
 9     std::string book_no;
10     unsigned units_sold = 1;
11     double revenue = 1.0;
12 
13 public:
14     Sales_data() = default;//不接受任何實參,默認構造函數
15     explicit Sales_data(const std::string &s): book_no(s){}//加了explicit關鍵字
16     Sales_data(const std::string &s, unsigned n, double p): book_no(s), units_sold(n), revenue(p * n){}
17     explicit Sales_data(std::istream&);//加了explicit關鍵字
18 
19     void out_put(std::ostream &os){
20         os << book_no << " " << units_sold << " " << revenue << std::endl;
21     }
22 
23     Sales_data& combine(const Sales_data&);
24 };
25 
26 Sales_data& Sales_data::combine(const Sales_data &rhs){
27     book_no += rhs.book_no;
28     units_sold += rhs.units_sold;
29     revenue += rhs.revenue;
30     return *this;
31 }
32 
33 std::istream &read(std::istream&, Sales_data&);
34 
35 Sales_data::Sales_data(std::istream &is){
36     read(is, *this);
37 }
38 
39 istream &read(istream &is, Sales_data &item){
40     double price = 0;
41     is >> item.book_no >> item.units_sold >> price;
42     item.revenue = price * item.units_sold;
43     return is;
44 }
45 
46 int main(void){
47     Sales_data cnt("hello");
48     // cnt.combine(cin);//error
49     // cnt.combine(string("world"));//error
50     return 0;
51 }

加了 explicit 關鍵字後 cnt.combine(cin);cnt.combine(string("world"));都是錯誤的。

explicit 關鍵字只對一個實參的構造函數有效。需要多個實參的構造函數不能用於執行隱式轉換,所以無需將需要多個實參的構造函數聲明成 explicit 的,雖然這樣做也並沒有語法錯誤。explicit 只能在類內聲明構造函數時使用,在外部定義時不應該重復。

explicit 關鍵字聲明的構造函數只能用於直接初始化:

Sales_data cnt(null_book);
Sales_data gel = null_book;

如果沒有將對應的構造函數聲明成 explicit 的話,這兩者初始化方式都是可以的,反之則只有值即初始化是正確的,而拷貝初始化是錯誤的。

為轉換而顯示的使用構造函數:

盡管編譯器不會將 explicit 的構造函數用於隱式的轉換,但是我們可以這樣的構造函數顯示地強制進行轉換:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class Sales_data{
 5 friend std::istream &read(std::istream&, Sales_data&);
 6     
 7     //數據成員
 8 private:
 9     std::string book_no;
10     unsigned units_sold = 1;
11     double revenue = 1.0;
12 
13 public:
14     Sales_data() = default;//不接受任何實參,默認構造函數
15     explicit Sales_data(const std::string &s): book_no(s){}//加了explicit關鍵字
16     Sales_data(const std::string &s, unsigned n, double p): book_no(s), units_sold(n), revenue(p * n){}
17     explicit Sales_data(std::istream&);//加了explicit關鍵字
18 
19     Sales_data &operator+=(const Sales_data &it){
20         book_no += it.book_no;
21         units_sold += it.units_sold;
22         revenue += it.revenue;
23         return *this;
24     }
25 
26     void out_put(std::ostream &os){
27         os << book_no << " " << units_sold << " " << revenue << std::endl;
28     }
29 
30     Sales_data& combine(const Sales_data&);
31 };
32 
33 Sales_data& Sales_data::combine(const Sales_data &rhs){
34     book_no += rhs.book_no;
35     units_sold += rhs.units_sold;
36     revenue += rhs.revenue;
37     return *this;
38 }
39 
40 std::istream &read(std::istream&, Sales_data&);
41 
42 Sales_data::Sales_data(std::istream &is){
43     read(is, *this);
44 }
45 
46 istream &read(istream &is, Sales_data &item){
47     double price = 0;
48     is >> item.book_no >> item.units_sold >> price;
49     item.revenue = price * item.units_sold;
50     return is;
51 }
52 
53 int main(void){
54     string cnt = "world";
55     Sales_data gel("hello");
56     gel.combine(Sales_data(cnt));//顯示地強制類型轉換
57     gel += Sales_data(cnt);
58     return 0;
59 }

 

類5(轉換構造函數)