|
一、转换构造函数的学习: 1、回忆数据类型转换: 在平时写代码的时候,最怕的就是那种隐式数据类型转换了,一不小心,软件就bug不断;而显式数据类型(一般是程序自己去强制类型转换,这个是我们能够明显的识别和掌控的)。为此我们这里总结了一副隐式类型转换的图:
下面我们来几个隐式转换的例子: 代码版本一: #include <iostream>#include <string> y5 r- F5 S7 F1 ^7 L% M ) R; ~8 ~4 H; s: s! A W int main() {# K' p! g' X/ D5 L, |) v2 B5 d short s ='a';2 Q6 ?9 j) T# X0 Q I, C8 { B unsigned int ui = 100; int i = -200; double d = i; @7 j" l: L0 [% U/ A std::cout<<"d =" << d <<std::endl;1 ]2 ~& H6 M) H; `2 {, ?! v/ X std::cout<<"ui= "<<ui<<std::endl;9 S9 x4 A2 g% N5 R% \, d1 c & L$ e7 x5 n; [0 q' W: a if((ui+i)>0)- M( l* U3 M r" }. U { std::cout<<" ostive"<<std::endl;, A$ X y' l( b6 g, `% p" l} else+ x9 y8 }- ^8 @' o( C9 Z9 n1 |& V {' t! V7 A3 l' f0 I( a/ L& ` std::cout<<"Negative"<<std::endl; } 0 N& ~% d" B& n) J0 U& o return 0;5 N& f5 r) p$ T } 输出结果: root@txp-virtual-machine:/home/txp# ./a.outd =-200, L# q' ]- I: r1 l2 t# B ui= 100 Postive. z% Q k9 I1 T$ V9 T& { & f' O2 v2 D, C3 Y 注解:这里我们明显发现(-200+100)还是大于0,这显然不符合正常人的思维了;所以我们仔细分析一下,发现这里肯定是进行了隐式转换了,为此我们再加一条语句看看(ui+i)的值到底是多少: 代码版本二: #include <iostream>& p& P: |2 Z. A, O; C; V#include <string> int main() {( \ f+ n: U. M short s ='a'; unsigned int ui = 100; int i = -200; double d = i; 2 ]% d b1 x- ~+ F+ y4 _# Q std::cout<<"d =" << d <<std::endl;4 t3 i6 T% E* v% s9 E) I7 a std::cout<<"ui= "<<ui<<std::endl; 2 e: q, r; y4 N3 A$ V7 H if((ui+i)>0) { std::cout<<"(ui+i) = "<<ui+i<<std::endl;0 E, z) r: h& l. f2 B# V std::cout<<" ostive"<<std::endl;}+ m8 _7 y5 V- [ else {% G" A0 i! t# z8 H3 S% U/ x6 V std::cout<<"Negative"<<std::endl;6 k+ w% v' q r# t } ( [- \0 H" M( l0 e3 W8 M' Y return 0; }; d$ x! y/ L& l5 Y" | ! f5 @* w x! K6 C/ o$ H C6 Q 输出结果: root@txp-virtual-machine:/home/txp# ./a.outd =-200 ui= 100 (ui+i) = 4294967196 Postive 注解:通过打印(ui+i)的值我们发现,i原本是int数据类型,这里隐式转换成无符号的数据类型了 为了让大家更加理解隐式的转换,我们下面再来一个例子: 代码版本三: #include <iostream>#include <string>) Q6 T) M' a i$ b int main()+ G+ D+ K) j7 H. g* m8 i( ^ {6 @/ N$ ~7 @* s& P8 K# j" }3 m short s ='a'; unsigned int ui = 100; int i = -200;3 s# m2 Q8 |( E0 q double d = i; % f6 D6 O$ f) ?. L M" M8 _, t std::cout<<"d =" << d <<std::endl;: n# |; ?0 [; F8 q1 N std::cout<<"ui= "<<ui<<std::endl; if((ui+i)>0)4 B. y' _, H; E {% r: i# O; Q% i$ `( ] std::cout<<"(ui+i) = "<<ui+i<<std::endl;* d& X7 V1 Q" b- T# }8 E std::cout<<" ostive"<<std::endl;3 y9 B; k, ?) J" H/ y, h}! B' h0 j# t6 u5 f. Y" P else1 Y- o! q& u0 a I {4 e: X1 \5 P w) w8 B! h std::cout<<"Negative"<<std::endl; } & M) h5 R5 b# Y std::cout<<"sizeof(s+'b') = "<<sizeof(s+'b')<<std::endl;+ f# ~3 ~7 w! H4 W h$ f8 h! _ return 0; }5 d2 }" c1 Y# e3 u4 \+ j # Z% G+ D; x4 E/ {8 Y% _1 | n 输出结果: root@txp-virtual-machine:/home/txp# g++ test.cpproot@txp-virtual-machine:/home/txp# ./a.out; N( ]0 H5 b0 n u" D5 A d =-200 ui= 100, ?& x8 X4 D% a. J& ^# X! n5 b (ui+i) = 4294967196% z& Q2 E' C/ @- a E4 ~0 u# l! w Postive sizeof(s+'b') = 4) T: m, |3 p* R; S) G. l* N w; w" u + `! M7 y5 V" ]" c 注解:这里我们发现sizeof出来的内存大小是4个字节大小;其实这里编译器把short和char类型的都转换int类型了,所以最终两个int数据相加,所占的内存大小就是int类型了。 所以咋们平时在写代码的时候,脑袋里面要有这种写代码谨慎的思维,防止出现这种隐式转换的情况出现,养成写代码的好习惯 2、普通类型与类类型之间能否进行类型转换,类类型之间又是否能够类型转换呢? 为了说明这些问题,咋们通过实际的代码测试来看看啥情况: 代码:普通类型转换成类类型 #include <iostream>#include <string>% n) `4 @9 _7 |! Z2 F( l0 B 1 n; {: V' Q1 f; z8 A& _& @( } class Test{ public: Test() {$ w+ ^( ~% x3 d( U$ i8 Q! }5 y 6 L; {9 \2 I8 `& [( P } Test(int i) {: {8 }- b/ ?- }1 C }5 r( y$ Z3 p# K0 U }; 3 M8 S9 W! `; Y0 |4 Y" \7 n int main() g, r5 e6 X9 Q( a9 \ { Test t;+ X; Z; v* I8 d2 E: a5 X t =6; 从 C 语言角度,这里将 5 强制类型转换到 Test 类型,只不过编译器 在这里做了隐式类型转换7 k6 M0 m9 l: w! r8 b' @ ` ( Z/ x& j% I4 V1 d ? return 0; } $ ]( C& p; i$ o: F- A9 \- J3 s/ } 输出结果(显示可以编译通过) root@txp-virtual-machine:/home/txp# g++ test.cpp& y) o" M* ~! G+ Yroot@txp-virtual-machine:/home/txp# ./a.out8 g& t) L& D& Y" n- m % I3 C4 W) w% S) I/ {: `2 r 代码类类型转换为普通类型 #include <iostream>. x" M; q+ m, X5 y% c3 u1 r. P* P#include <string> class Test{ public: Test(); K$ d, A4 f! Q4 j2 ?" ` {7 t) W5 {1 n( i / v' Y& X9 S6 A* G3 f/ N } Test(int i) {9 W9 D5 s7 G3 P' ` }( p) J: h" ^% n4 \ }; * e, \8 `/ `8 s/ t; N int main()6 z* g0 V% a5 S5 t9 A/ ]+ b5 m! w { Test t; $ K/ w) E; k2 F/ i0 K9 U! ^ int i = t; return 0;9 U! L$ \- C5 y! x, e A- r }2 U9 ~* D. f2 P% z3 O . r& M& T3 n3 Q" v N$ \( X. P2 I 输出结果(没有编译通过) root@txp-virtual-machine:/home/txp# g++ test.cpptest.cpp: In function ‘int main()’:3 M8 N+ I1 u& O+ G5 A test.cpp:21:14: error: cannot convert ‘Test’ to ‘int’ in initialization7 B+ m5 @7 D" B# z I int i = t;7 j- @+ O6 U! e( y8 n ^, {# ] d! {( G% Y* H8 e& b# x 9 { g' ?/ d1 }5 n% K' | 代码类类型与类类型之间的转换: #include <iostream>0 R7 F# r; Y+ A8 n+ S0 a8 I#include <string>) t3 Z m9 i$ q0 Q5 M! w o! b 2 e O9 V& @' [8 l7 Q class Value{/ [& D5 t2 }4 ]3 I s };( w% B8 f. _( p$ f . O9 J5 S6 `, `3 l. E# I1 x1 Y : r. S8 M2 e, z2 I6 U class Test{: T/ w+ B# T3 b: u$ [/ }/ | X public: Test() {4 T- y6 |4 F# L Q0 x, Z& B1 x+ x }! z. I6 ]8 ~3 A+ v1 U/ {) e" F m- M Test(int i)9 T6 v; z& E9 t# n* }6 v+ x {% F; l: k) V6 [9 B1 ~' } ( N( L1 M, F6 d7 C% P# K& t: ] D } };2 o) L7 Z2 t3 p# U5 @ int main()# s. p/ Y! h& n0 C. O {3 N4 F: Q5 }1 p9 v* C; r% t Test t;+ U. l2 S) C& z ]: g Value i;2 T6 m. q$ P- ~) ^ * V+ I) l/ I5 O8 r. T: r t=i;* a$ ]2 D3 m" V1 I1 |5 E ( }' r3 [8 O' [5 k1 i: l$ Y return 0;5 n, F$ `3 c, H; f5 k } , u3 c( ?4 X; g4 U0 V6 O. l4 a 输出结果(暂时还是不行,编译不通过): root@txp-virtual-machine:/home/txp# g++ test.cpp: f/ O0 T# x4 d4 P' Jtest.cpp: In function ‘int main()’:# c3 v" q7 H& T: | test.cpp:27:7: error: no match for ‘operator=’ (operand types are ‘Test’ and ‘Value’)+ C7 x% t5 z5 f; F% ? t=i; ^ test.cpp:27:7: note: candidate is:3 C7 z: q. w9 I test.cpp:9:7: note: Test& Test: perator=(const Test&)class Test{- T7 m% R. W! ^) o) w5 \ ^/ l8 j* b0 w. ] test.cpp:9:7: note: no known conversion for argument 1 from ‘Value’ to ‘const Test&’6 L' D3 ^$ P* _7 z: U- L 说明:上面的例子,我们只是简单的按照实际角度出发,发现确实有写转换行不通。那么真理到底是怎样的?我们接着往下看 3、转换构造函数出厂: 我们前面学习过构造函数,构造函数它可以定义不同类型的参数;但是我们今天这里所说的转换构造函数的定义时这样的:
接着我们对上面的普通数据类型转换类类型的代码进行分析: #include <iostream>( P, y& f! ?2 a# e. V! ^#include <string>: A8 E7 M! _8 | ' @1 i$ Z6 l9 [ class Test{ 6 Z9 ]9 S; K' d, v* w/ ^3 Z public: Test() { 0 k4 G: F- n0 Z/ w6 u* _ }0 f& ?6 h8 c' a/ M9 e) \ Test(int i) {: C9 u J l2 d }* G) ?7 W7 R, U( K! S };& L# q7 d5 ^( y$ t4 Y$ w, V: m! O8 L ( \$ z3 J' R% ^- v! C* D' ]* ^ int main() k0 L7 S: `( r; ? B { Test t; / o$ [$ V( k* {' S% a3 g t =6; //从 C 语言角度,这里将 5 强制类型转换到 Test 类型,只不过编译器 在这里做了隐式类型转换5 Z, ?5 \6 `: y1 x u# \ 0 }. d8 S3 S4 w return 0; } 分析: 上面的Test(int i )就是一个转换构造函数,所以我们上面的这句隐式转换语句: t =6" q* x5 |' x# U Z: T( V% W这里其实发生了我们刚才说的利用了转换构造函数,把6转换成Test(6),而这样写就会产生一临时对象,所以就可以进行赋值了;但是在现在的技术发展中,肯定是不希望出现这种要人去防止这隐式转换,所以在c++中有了新技术来防止出现隐式转换:
代码实践一: #include <iostream>#include <string>" O$ Q( ], l7 `- Q2 K. i X% F1 Z class Test{/ L7 e: y. e! B# W 2 Q7 u& w% k+ m" v \+ K public: Test()+ Z: u9 X- f6 i& h+ W {) S; l; S# @! V7 R8 V- z: S0 u" A 8 c" h8 H% w# Q' j/ A& m5 E }; [: M3 U2 w* O" p; Y9 U explicit Test(int i) { } };/ M- Y V& _1 F N : @( r' O8 V* F. v int main() { Test t;9 M/ @" \7 B# I/ J" y! h " l# r" G7 m/ n, E: F t =6;$ f2 b" \$ B! a" p2 g% U return 0;4 ^9 Q/ O, Z0 ]- I6 ~! x; t }3 \6 Y# S. y+ u9 v5 e 输出结果: root@txp-virtual-machine:/home/txp# g++ test.cpptest.cpp: In function ‘int main()’:9 m" e- d* \% Q! p! N test.cpp:21:8: error: no match for ‘operator=’ (operand types are ‘Test’ and ‘int’)0 P S: ^1 y; C: T/ z9 l% M t =6; ^ test.cpp:21:8: note: candidate is:" o: S' a9 r" L7 L test.cpp:4:7: note: Test& Test: perator=(const Test&)( c5 W0 h( H# w; Gclass Test{ ^ test.cpp:4:7: note: no known conversion for argument 1 from ‘int’ to ‘const Test&’ + @; V9 t3 e3 O; q2 ?$ _ 注解:这里显示不能这样转换 代码实践二(进行显示转换): #include <iostream>#include <string> ; G; W( q* F4 q$ F class Test{ " L7 E% x6 T3 {* l( a. o public: Test() { $ ]' L; n m& t8 j1 J& _1 v }7 }& Q+ I) {% c/ }" x9 ~- f0 Y explicit Test(int i). Y. W1 \( t, H3 b { , j& l5 t( ~* R V } };+ }. j3 p Z0 b) e5 Y. N% } int main()5 R+ |; x. y; z' Q R" N$ ~& A { Test t;) e4 @: R n% f' e/ l2 p6 ~ 1 y9 d; ^: l1 Q9 c: Y0 _9 \ t =static_cast<Test>(6);5 h4 S! F0 y, F! ?% c return 0; } 输出结果(编译通过): root@txp-virtual-machine:/home/txp# g++ test.cpproot@txp-virtual-machine:/home/txp# 4、小结:
二、类型转换函数: 1、类类型转换普通类型: 在我们上面通过代码测试发现不行,那么是真的不行吗,事实是可以进行转换的,不过要用到我们现在c++里面的类型转换函数(它用于将类对象转换为其它类型),类型转换的语法如下: operator Type()9 p) w8 D- M: l{# E7 Y- R2 T F+ h Type ret; 6 Y: b4 @1 \8 j- L. b4 _ return ret;1 E8 V- A7 a& S7 a % U3 _! ^+ c9 K. w/ o: \- d1 q/ o0 _) H }3 F9 Z1 E, P1 u& H 代码实践: #include <iostream>, o7 p/ `9 C, }( b4 y# x, V#include <string>$ z8 u! _+ h; @+ o4 p class Test{ / b9 f7 L/ E0 }. B! l public:6 X9 e" w1 y4 h( V3 n0 a Test() { }* x V5 s; `9 Q& Q* f: b- h1 B operator int() {5 k0 I( C, `* X5 m3 m1 Y5 p7 k % g8 n8 d' ]0 o5 s# W* b } }; int main() {( j) o# T4 h% B+ g4 T k4 b Test t; int i =t; return 0; } 输出结果(编译没有报错): root@txp-virtual-machine:/home/txp# g++ test.cpproot@txp-virtual-machine:/home/txp# 注:
2、类类型之间的转换: 这个问题也是之前我们上面简单的测试,不能进行类类型之间的转换;现在我们学习了类型转换函数,是可以进行转换的: 代码版本一: #include <iostream>$ b. X( s$ d, ]7 l% s' M#include <string>* o3 B0 @+ Z! _# @7 V9 o 3 V* j# ]& K6 K) R: p using namespace std; ! g* b# q8 X9 t- Y/ a2 R class Test; class Value {6 `* {$ }/ {* G; }; L public: Value() { }5 k. Y7 j/ R5 ]* T: { explicit Value(Test& t) {0 N* T& B) K; T } }; class Test {. k1 K7 e7 f$ A# h; V int mValue;: v; g2 X+ U1 U5 A+ U1 I4 i public:6 c% u# z& j. u; b, Y, N+ I Test(int i = 0)( g5 Z7 o+ a9 \ {& p% Z) v7 F/ n5 w- m mValue = i; }# a. A& {, u" W' b5 b* e4 ~$ l int value() {2 s; z/ n, D9 {( z return mValue;5 v& o; x$ _8 L } operator Value()% D" m: |( g) g5 C& Z, A- L { Value ret;. S4 x! p* D: ^ cout << "operator Value()" << endl; return ret; }8 U; M6 Q- F% [1 e+ X# G/ @ /*工程上通过以下方式;7 K1 E7 b* T. _. B' N! Q; \, ? Value toValue() { Value ret;5 e+ d' H; h& g+ Y# J & L6 M) i, Z. [, s0 \4 _2 \ V" ? return ret;5 L( k9 k4 k. l C } }; int main()7 x% F. t$ \: m2 s { 4 g& I+ j2 X, A" B0 O Test t(100); Value v = t; return 0;9 O1 L x4 E0 ^ c. P% b } " K2 c$ ^3 G. T; ~0 w( N 输出结果(编译通过): root@txp-virtual-machine:/home/txp# g++ test.cpp% y- X. `/ F6 R$ a2 b: r8 Kroot@txp-virtual-machine:/home/txp# . z0 k( q* j) u ) Y2 g. U1 E7 q6 [7 @+ ? 注意:这里还有一种让编译器犯难的转换写法;我们上面这样写是用explicit关键字屏蔽了Value类里面的隐式转换,所以不会犯难,下面是犯难的代码示例: #include <iostream>1 A! ]- f; K3 ~1 x#include <string> using namespace std;4 j4 h4 m7 U& E# C9 ] class Test;9 T, T `+ W* i0 m1 Z * n: E2 D: `7 N class Value { public:- F/ d% @% C) J6 M1 `; s( V Value()' o* b$ V$ |; r* _ { } Value(Test& t) { } };/ u. u* W+ v4 d- }/ S + K0 A1 w$ a. w$ m6 | class Test# M: A: r) s1 S3 n {+ Q8 |5 H R" _, Z5 ~ o' { int mValue; public:+ o5 U a/ t# G Test(int i = 0)5 R# t% V7 F+ [& e4 \- w& A { mValue = i;+ [) I: u+ @7 G' e2 i } int value()4 T2 e. S' l& c9 a5 o: C+ k { return mValue; } operator Value() { Value ret; cout << "operator Value()" << endl; return ret; } }; * X' y* p& ^& l6 s int main()# S- p' j X2 i! a2 h { 2 a; [4 p4 X h; c5 D9 n% o8 x Test t(100); Value v = t; & r* w3 ]6 ^0 C3 O8 A3 r l return 0;/ T: r# E, n( V! K+ X% Y } 输出结果: root@txp-virtual-machine:/home/txp# g++ test.cpptest.cpp: In function ‘int main()’: test.cpp:42:15: error: conversion from ‘Test’ to ‘Value’ is ambiguous Value v = t; ^ test.cpp:41:10: note: candidates are:& E9 e4 ?- Q) g Test t(100);- K8 g. r$ A$ C# N; H- {$ X4 [ ^ test.cpp:31:5: note: Test: perator Value()operator Value() ^ test.cpp:14:6: note: Value::Value(Test&) Value(Test& t) + S9 Z! J& p' b! z. R/ I0 D 3、小结:
好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。 / T9 q- h% D" R2 _: Y5 P |
微信公众号
手机版