类5(转换构造函数)

转换构造函数:

当一个构造函数只有一个参数,而且该参数又不是本类的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 }
 
原文地址:https://www.cnblogs.com/geloutingyu/p/8150019.html