++ . Tác gi : Giáo viên h ng d n: Sinh viên d ch:
Mats Henricson and Erik Nyquist. Th y Nguy n T n Tr n Minh Khang. Lê Quang Song.
! "#" $% &' !: • • • •
• •
• •
• •
1. % % ()%*'(Introduction) 2. )'+( !,(Terminology) 3. - ". ")' !(General Recommendations) 4./0 !'1 (23 ! ), ! 4%56(Source Code in Files) * 4.1. ' (27" 80(Structure of Code) * 4.2. 9 ), ! 4%56(Naming Files) * 4.3. ), ! 5:% !% % ();")(Comments) * 4.4.I "5'&6 ), ! 4%56(Include Files) 5. ), ! (9 !# (Assigning Names) 6.<)3 ! "#")(Style) * 6.1. #" 5 =(Classes) * 6.2. #" )>8(Functions) * 6.3.?)@% 5* ) A%-' B)%C (Flow Control Statements) * 6.4D 3 (2E F> ()G8 ")%H'(Pointers and References) * 7.1.Quy-n truy c+p(Considerations Regarding Access Rights) * 7.2.H>8 Inline(Inline Functions) * 7.3. #" )>8 IJ (Friends) * 7.4. >8 )K ! ()> ) F%9 (const Member Functions) * 7.5. >8 B)L% (J3M)>8 )NO(Constructors and Destructors) * 7.6.T3# (. gán(Assignment Operators) * 7.6. '# ( % (3# (.(Operator Overloading) * 7.7.?%C' (2 F- "NG )>8 ()> ) F%9 (Member Function Return Types) * 7.8.KH ()PG(Inheritance) 8.Q = (68=5G(6R(Class Templates) 9. >8(Functions) * 9.1. @% R@ "NG )>8(Function Arguments) * 9.2. '# ( % )>8(Function Overloading) * 9.3. @% R@ )S ) ()T"(Formal Arguments) * 9.4.Gi# (2 F> B%C' (2 F-(Return Types and Values) * 9.5.Hàm inline(Inline Functions) * 9.6. ), ! A@% ( U ! (J8 ():%(Temporary Objects) * 9.7. Vng quan(General) 10. K !(Constants) 11. %H (Variables)
• • • • • •
•
12. 3 (2E F> ()G8 ")%H'(Pointers and References) 13.Ép B%C'(Type Conversions) 14.?)@% " ' (27" A%-' B)%C (Flow Control Structures) 15. %C' ()T"(Expressions) 16. = =)#( I$ ) (Memory Allocation) 17./0 5% ) A$ !(Portable Code) * 17.1.W, 5%*' (2P' ( U !(Data Abstraction) * 17.2.?;"B "X "NG B%C'(Sizes of Types) * 17.3. )'OC AV% B%C'(Type Conversions) * 17.4./Y ( &, 5%*'(Data Representation) * 17.5. Underflow/Overflow *17.6. @% ( U ! (J8 ():%(Temporary Objects) *17.7. 3 (2E R@ )Z"(Pointer Arithmetic) 18.[#") ()G8 B) 3(References)
1.GI\I THI]U(INTRODUCTIONS) /^" A;") "NG (>% 5%*' >O 5> _#" A ) 8$( =)3 ! "#") 5+= (2S ) (23 ! ++D ), ! `'% (a" F> ), ! A". L AbO B)Y ! =) % 5> ( ( " ) ! c "' ! " = ), ! B%H ()T" "d I AC 5>8 F%*" F % ++D += )U= ), ! `'% (a" >O Re 5> ), ! (>% 5%*' f ! A$ !MB)'OH B);") Rg =) ( (2%C thêm. ), ! O9' " ' F-
), ! `'% (a" 8 % )GO ), ! Rg ()GO AV% "#" `'% (a" A U" BC AH !) "h ! "c ()C !L% AH ")7 ! (Y% `'G A G ")i 8G%5 ) RG' : • •
) 5> =)^ 5^" "NG (>' >O. ), ! A-
[email protected] [email protected]
), ! ") d ! (2S ) A U" =)#( (2%C ()63 "#" `'% (a" F> ), ! (%H ". L AbO Re: j 7 !. * /G ! (; ) (#% R. &^ ! C AJ( AH Rg "); ) _#"M") d ! (2S ) 9 : * c 8$( =)3 ! "#") ) ( `'# . * W &> ! AZ" F> )%C'. j ?) f ! ")'OC AV% !%,G "#" !Y !,. j J3 2G ), ! ()Y ! I#3 5k% =)V I%H . j c ()C &'O (2S IL% ), ! )> 5+= (2S ) B)#" )G'. ), ! "b' )E% (23 ! F%*" ()%H( BH ) 5> l5>8 ()H >3 AC ()%H( BH 8$( 5 = )3m" An ! " = "NG 5 = K8 !3>% (>% 5%*' >OD c ()C ()G8 B) 3 ), ! R#") (23 ! A U" !% % ()%*' "'@% (>% 5%*' >O. ), ! !S ")TG Ag ! I9 (23 ! (>% 5%*' >O Re ")i 2G "#") ) ()H >3 AC !% % `'OH( "c )%*' `' ), ! B);G "J ) B)c B)f ) ( trong C++D =) % a8 Ia( F> )Z" Bo ), ! F; &^ F- ), ! A3J 80 F; &^ A U" "' ! " = L AbO.
2.THUpT NG (TERMINOLOGY) 1. M$( I%H ,)K ! M)>8 )3m" 8$( B%C' trong C++ A-' "c 8$( nh danh (identifier) hay 5> 8$( (9n riêng D?)% " ()%H(, 8$( A ) &G ) "c " ' (27" $% I$ "c !)oG 5> "c "#" (%- (@ M(9 F> "#" )+' (@ (23 ! Ac.q )63 ()T (g)
2.Class 5> 8$( B%C' &, 5%*' &3 ! :% &r ! (g A ) !)oG IG3 !18 "#" &, 5%*' F> "#" )>8 ()g" )%* (29 "#" &, 5%*' Ac.Trong C++ ,AbO "c 5e A U" B)G% I#3 ) 8$( 5 = M c "h ! A U" B)G% I#3 ) 8$( " ' (member (27"(struct) )GO 8$( union .W, 5%*' A U" A ) !)oG (23 ! 5 = A U" !Z% 5> data) . > ), ! )>8 A U" A ) !)oG (23 ! 5 = A U" !Z% 5> "#" (member functions) . sD/$( class/struct )3m" union A U" c% 5> "#" B%C' &, 5%*' (2P' ( U !(abstract data type) ")7 ! B)Y ! "c I ( BS 8$( >3. (public or protected member data.) tD/$( struct "h ! 5> 8$( B%C' &, 5%*' &3 ! :% &r ! A ) !)oG ) "$ ! (public data)8> ()Y%.
! ")7 ! ")i ")TG &, 5%*' "Y !
5. Public members "NG 8$( 5 = 5> "#" &, 5%*' ()> ) F%9 ( member data)F> "#" )>8 ()> ) F%9 (member fuctions) "#% 8> "c ()C A U" R. &^ ! 8Z% d% . 6.Protected members "NG 8$( 5 = 5> "#" member data F> "#" member functions 8> "#" )>8 ()> ) F%9 "NG 5 = !@" 8 % (2'O "+= A U" . uD/$( class template A ) !)oG 8$( )Z "NG ), ! 5 = D/$( 5 = 8 % A U" Re A U" (J3 (P class template IK ! F%*" "' ! " = 8$( R@ "#" A@% R@. ), ! !%# (2 >O "c ()C 5> (9 "NG ), ! B%C' )GO "#" I%C' ()T" )Kng. vD d ! (g 8$( functions template A ) !)oG 8$( )Z "NG ), ! )>8D/$( )>8 8 % Re A U" (J3 (P functions template IK ! F%*" "' ! " = 8$( R@ "#" A@% R@D ), ! !%# (2 >O "c ()C 5> (9 "NG ), ! B%C' )GO "#" I%C' ()T" )K( B%C' enumeration type 5> 8$( B)G% I#3 2w 2> ! (+= )U= A O AN B; )%*' )K !. 23 ! xx c A U" B)G% I#3 5> enum. 10./$( typedef 5> 8$( (9 B)#" ")3 8$( B%C' &, 5%*' M(23 ! xx ()S B)G% I#3 5> typedef . 11./$( ()G8 ")%H'(reference) 5> 8$( (9 B)#" ")3 8$( I%H .Trong C++ M(3# (. A G ")i (&) A U" B)G% I#3 !GO RG' B%C' &, 5%*' AC ")i 2K ! A0 B)G% I#3 8$( I%H M)K !MA@% R@ "NG )>8 5> 8$( ()G8 ")%H'. 12./$( (macro) 5> (9 ")3 8$( ")'k% Ff I n "#% 8> A U" A ) !)oG (23 ! B)G% I#3 #define . ?)% (9 >O _' ( )%* trong A3J 80M(2S ) I%9 & ") Re ()GO ()H c & % &J ! Ff I . 13 Constructor 5> 8$( )>8 B)L% (J3 ")3 8$( A@% ( U !. 14.Copy constructor 5> )>8 (J3 I RG3 Ac 5> 8$( )>8 B)L% (J3 (23 ! Ac A@% R@ A ' (%9 ()G8 ")%H' AH A@% ( U ! "r ! B%C' F % A@% ( U ! A U" B)L% (J3 . 15. >8 B)L% (J3 8m" A ) 5> )>8 B)Y ! "c A@% R@. 16.Overloaded function name 5> `'# ( % (9 )>8 "c !)oG 5> (9 A U" R. &^ ! ")3 )G% )GO )%-' )>8 ) ! B)#" ()G8 R@ (2'O- F>3 F> B%C' (2 F-. 17.Overridden 5> )>8 ")1 ! "c !)oG 5> 8$( )>8 ()> ) F%9 (23 ! 5 = "d RL A U" A ) !)oG 5J% (P 5 = !@". )7 ! 5> "#" )>8 3(virtual).
18.Pre-defined data type 5> B%C' &, 5%*' "c (23 ! !Y
!, MF; &^ int ,float…
19.User-defined data type 5> B%C' &, 5%*' &3 ! :% &r ! A ) !)oG ) 5> :class,struct… 20.Abstract base class 5> 8$( 5 = 8> B)Y ! A@% ( U ! >3 "c ()C (J3 M c ")i A U" R. &^ ! ) 8$( 5 = "d RL ")3 F%*" (S8 2G 8$( 5 = B)#".
3.
(General Recommendations)
- ". 1: @% ' 80 B)% IJ ")i B)% IJ IJ "c Rg ()g" ()% "c F A-. ['O !)o )G% 5 (2 " B)% IJ Ia( A '. - ". 2: H' IJ R. &^ ! (2S ) I%9 & ") ++ trên Cfront M5'Y 5'Y I%9 & ") F % ": )%*' +w ()%H( 5+= "#" OH' (@ 53J% IE B)% 8$( F>% I#3 A$ ! "c ()C. )%-' "'$" B%C8 (2G ")3 () O c% ")' ! )%-' )> 5+= (2S ) A0 (@ 2 ( )%-' ():% !%G AC (@% ' ), ! A3J 80 "#% 8> ") G IG3 !%: A U" ")JOD H' ") d ! (2S ) "NG IJ `'# ")+8 MR. &^ ! gprof++ )3m" "Y ! "^ ( d ! (g AC _#" A ) "); ) _#" I ") ( "NG ), ! F A- (2 " B)% (@% '.
4./y 4.1.
{ Q|(Source Code in Files)
z
' (27" "NG 80: '% (a" 1: ), ! 4%56 ")} F>3 trong xx 5'Y 5'Y "c (9
4%56 "c A'Y% 8L 2$ ! “.h”.
'% (a" 2: ), ! 4%56 ()g" ()% trong C++ 5'Y 5'Y "c (9 4%56 "c A'Y% 8L 2$ ! “.cpp”. - ". 3: /$( % "5'&6 4%56 B)Y ! 9 ")TG )%-' )d 8$( 5:% A ) !)oG 5 =. - ". 4: )%G ), ! A ) !)oG "NG ), ! )>8 ()> ) F%9 )GO ), ! )>8 ()> ) )%-' file kh#" )G' H' "c ()C. - ". 5: m( ), ! 80 8#O A$" 5+= 59 ), ! 4%56 B)#" )G' AC & &> ! _#" A ) F (2; B)% 8G ! AH 8#O B)#".
/^" A;") "NG ), ! `'% " >O 5> AC "' ! " = Rg ()C )%* A1 ! ) ( "NG ), ! (9 file. /$( 5; &3 ")3 A%-' >O Ac 5> & &> ! ()G3 (#" ), ! "Y ! "^ (29 (9 4%56 "c A'Y% 8L 2$ ! Ac. c )G% 53J% 4%56 include trong C++ l ), ! "#% A U" ") = )+ trong " (2S ) I%9 & ") ANSI-C F> C++ FG ), ! ()T ")i A U" ") = )+ (23 ! (2S ) I%9 & ") xx 8> ()Y%.W3 Ac =) % =)b I%*( AC (2# ) 5k% (23 ! "#" 4%56 % "5'&6(&3 R. &^ ! RG% 53J% 4%56 ")} F>3). H' ) 8$( 4%56 "c A'Y% 5> .cpp ")TG )%-' A ) !)oG )>8 M8$( 4%56 A@% ( U ! A U" (J3 ra 5 B)Y ! " ()%H(. C ()' A U" 8$( 4%56 ()% )> ) )E ) ( "c ()C ()S " =) % A ) !)oG ), ! )>8 (29 ), ! 4%56 2%9 ! I%*(. ! U" 5J%M"c ), ! F A- (23 ! F%*" `' 5; 8$( R@ 5 "#" 4%56 Ac ,():% !%G " ()%H( AC I%9 & ") "#" 4%56 Ac Re 2 ( 5b'. /$( F>% ") d ! (2S ) !X 2@% Re B)Y ! !X 2@% A U" I9 (23 ! ()b "NG ), ! )>8 D K ! "#") Am( ), ! )>8 Ac (23 ! ), ! 4%56 B)#" I%*( F> % "5'&6 c F>3 4%56 I%9 & ") ,FS F+O Re _. 5; ()b "#" )>8 ) ), ! )>8 ()Y ! () : ! F> &3 Ac Re !L 2@% A U" ), ! )>8 (23 ! B)% B%C8 (2G ") d ! (2S )DD C 5>8 "Y ! F%*" >O 8$( "Y ! !)* _. 5; Am( I%*( =) % A U" R. &^ !. ?)% ), ! "Y ! "^ `' 5; 80 ++ 5> B)Y ! ()CM()+( 5> & &> ! )d ")3 ), ! G% R. &^ ! F> I 3 (2S ), ! 5 = H' ")i "c 8$( 5 = (29 8$( 4%56 2%9 ! I%*( F> H' Rg ()% )> ) ), ! )>8 ()> ) F%9 (23 ! ), ! 5 = B)#" )G' )%* (J% B)Y ! K8 "r( 4%56.
4.2.Tên file - ". 6: Q'Y 5'Y Am( (9 4%56 "#% 8> A$" ) ( (23 ! 8$( !. "
)5
"c ()C.
- ". 7: /$( 4%56 ")} F>3 ")3 8$( 5 = "c (9 "c &J ! :~(9 5 =• xA'Y% 8L 2$ ! . [. &^ ! ), ! B; (g )3G F> () : ! ()63 "r ! 8$( "#") ) (23 ! m0 !'1 . P B)% (9 "NG ), ! 5 = =) % R. &^ ! ()@ ! ) ( (23 ! 8$( !, " ) 5 M()+( 5> ();") )U= AC R. &^ ! ), ! Am" A%C8 >O ")3 F%*" Am( (9 "NG ), ! 4%56 ")} F>3. %-' >O Re !%7= ), ! "Y ! "^ 4%56 "d I A ) F 5 = 8$( "#") & &> !.
tDsD ), ! 5:% ")7 ();")(Comments) '% (a" 3: /k% 4%56 ")TG Ag ! 80 !'1 =) % "c 8$( (>% 5%*' (23 ! Ac "c ), ! 5:% ")7 ();") !% % ()%*' F- "#" ()Y ! (% "NG 4%56 F> $% &' ! "NG c. '% (ac 4: ( " "#" 4%56 ")} F>3 =) % IG3 !18 ()Y ! (% F- I '% (a" 5: ( " "#" 5:% !% % ();") =) % F%H( IK ! (%H ! € ). - ". 8: %H( 8$( F>% ")7 ();") 8Y ( (2 - ". 9: [. &^ ! •• ")3 5:% ")7 ();").
" 8k% )>8.
`'O- .
c 5> Rg " ()%H( ")3 8$( (>% 5%*' 80 !'1 D %-' >O A U" ")m( ")e F> & (S8D %*" ")Z A7 ! "#") ")3 ), ! (9 I%H M )>8 F> 5 = F> A7 ! "#") " ' (27" 80 ()S Re " ;( 5:% !% % ();") (23 ! A3J 80. )7 ‚ 2K ! ), ! 5:% !% % ();") (23 ! ), ! 4%56 ")} F>3 5> "c ‚ !)oG ")3 ! :% R. &^ ! ), ! 5 = M(23 ! B)% Ac ), ! 5:% !% % ();") (23 ! 4%56 ()% )> ) "c ‚ !)oG ")3 ), ! ! :% I 3 `' 5 =. ( " A3J 80 "NG ")7 ! (G =) % "c I `'O- 2w 2> !D H' ), ! A3J 80 A U" =)#( (2%C `'# 8$( ")' BS ), ! nfmM8k% f8 =) % Ia( A '. ), ! 5:% !% % ();") () : ! A- "+= ), ! F> ./$( 5:% !% % ();") ")%H 5 U" 8Y ( )>8 5> !S F> =) !S "NG A3J 80 A U" &g A ) AC 5>8 F> ), ! !S A U" ()GO ()H RG' A3J 80 >O./$( 5:% !% % ();") R#") 5 U" 8Y ( 8$( &ƒ ! Ad "NG 80 ), ! !S A U" &g A ) 5>8 F> ), ! !S A U" ()GO ()H M H' "c ()C , "'@% 8k% &ƒ ! >O. %H" ()GO , H' `'# )%-' 5:% ")7 ();") ) F+O Re 5>8 ")3 ), ! A3J 80 B)c AZ". @% F % 5; &3 >O ,"c 8$( A- ". 5> ")N OH' R. &^ ! ), ! 5:% !% % ();") ")%H 5 U" M(2P B)% "@ !% % ();") ), ! A3J 80 2 ( =)T" (J=. H' ) ), ! B; (g // ) ( `'# R. &^ ! ")3 ), ! 5:% !% % ();") MRG' Ac "c ()C R. &^ ! Rg BH( )U= /* */ AC 5>8 ), ! 5:% !% % ();") !3>% (3> I$ =) 80 (23 ! R'@( !%G% A3J =)#( (2%C F> !X 2@%. ; &^ 1: >% 5%*' "NG 4%56: // // // // // // // // // // // // // // // // // // // // // //
File: test.cc /Y ( : This is a test program Rev: A U" (J3: Thur. Oct 31, 1991, 12:30:14 #" !% : Erik Nyquist mail:
[email protected] `'O- : Ellemtel Utvecklings AB 1991 BOX 1505 125 25 ALVSJO SWEDEN tel int + 46 8 727 3000 The copyright to the computer program(s) herein is the property of Ellemtel Utvecklings AB, Sweden. The program(s) may be used and/or copied only with the written permission of Ellemtel Utvecklings AB or in accordance with the terms and conditions stipulated in the agreement/contract under which the program(s) have been supplied.
; &^ 2:Q:% !% % ();") ")%H 5 U" F> R#") 5 U"(Strategic and Tactical Comments) // THE NEXT TWO LINES ARE STRATEGIC COMMENTS // This function does some complicated things. It works like this: // blah-blah-blah ... int insanelyGreatAndComplicatedFunction( int i ) { int index = i++ + ++i * i-- - --i; // THIS IS A TACTICAL COMMENT return index; }
4.4. ), ! 4%56 ")} F>3(Include files) '% (a" 6: /k% 4%56 ")} F>3 =) % ")TG 8$( "d ")H !f ")m (; ) I$% "NG "#" 4%56 ")} F>3 Ac. '% (a" 7: )63 ), ! 53J% A ) !)oG A U" R. &^ !q(23 ! 4%56 I%9 & ") F> 4%56 ")} F>3) M")7 ! =) % A U" ")} F>3 8$( "#") (#") I%*(: • ), ! 5 = A U" R. &^ ! ) ), ! 5 = "d RL. • ), ! 5 = A U" R. &^ ! ) ), ! I%H ()> ) F%9 . • ), ! 5 = _' ( )%* ) B%C' (2 F- )3m" ) 8$( B%C' A@% R@ (23 ! !'O9 8 ' )>8 )3m" )>8 ()> ) F%9 . • !'O9 8 ' )>8 ")3 )>8 )GO )>8 ()> ) F%9 R. &^ ! (23 ! )>8 ()> ) F%9 inline A U" A ) !)oG (23 ! 8$( 4%56. '% (a" 8: ), ! A ) !)oG "NG ), ! 5 = "#% 8> ")i A U" (2'O _' ( `'G "3 (2E (*) )GO ()G8 ")%H'(&) Re không A U" ")} F>3 (23 ! 4%56 ")} . '% (a" 9: ")i A ) ), ! ()T 5%9 `'G AH tên UNIX (23 ! ")i () #include '% (a" 10: /k% 4%56 ()% )> ) 5> IG3 !18 ), ! 4%56 5%9 `'G : • ), ! B)G% I#3 "NG ), ! B%C' F> ), ! )>8 R. &^ ! (23 ! ), ! )>8 A U" ()g" ()% (23 ! 4%56. • ), ! B)G% I#3 "NG ), ! I%H F> "NG ), ! )>8 ()> ) F%9 R. &^ ! (23 ! ), ! )>8 A U" ()g" ()% (23 ! 4%56.
- ". 10: [. &^ ! ")i () #include ” filename.h ”")3 ), ! 4%56 ")} F>3.
- ". 11: [. &^ ! ")i () #include < filename.hh >")3 ), ! 4%56 (23 ! () F%* . - ". 12: P ! IG3 !%: ")} 4%56 B)#" (23 ! file “.cpp” -/$( "#") & ) ( AC B)Y ! I 5m= 5J% "#" 4%56 ")} F>3 ()S &r ! B)@% # ifndef #define F>3 A ' "NG 4%56 F> #endif "'@% 4%56. -[@ 4%56 ")} F>3 9 )EM H' ) 8$( 4%56 A U" ")} F>3 (23 ! 8$( % "5'&6 4%56M RG' Ac (23 ! 8k% 4%56 ()% )> ) A G F>3 ), ! 4%56 ")} 5 ()T )G% F> c Re I%9 & ") 5J% 8k% B)% 4%56 A ' (%9 I ()GO AV%. /$( Rg ()GO AV% Ad !% (23 ! 8$( 4%56 "c ()C 5>8 c " ()%H( AC I%9 & ") 5J% 8$( R@ 4%56 5 )d . - H' 8$( file ")i ")TG ), ! ()Y ! (% ")i " ")3 ")3 4%56 I%9 & ") ()S B)Y ! 9 A G F>3 I ( "T 4%56 ")} >3. -<) I%*( Rg B)#" )G' !%,G ), ! ")i () ")} F>3 5> "NG ! :% &r ! (g A ) !)oG )GO 5 O (P () F%* D H' (9 4%56 ")} F>3 K8 !%,G )G% & ' “< “ F>” >” ()S I$ (%- _. 5; Re B)Y ! (S8 () O 4%56 >O (23 ! () 8^" 8m" A ) . %-' >O Re & AH 8@% !'O )%C8 B)Y ! I#3 (2 " A U" 5> Rg _' ! A$( 5 )G' !%,G (9 &3 ! :% &r ! A ) !)oG F> (9 (23 ! () F%* ")} F>3. - K ! F%*" B)G% I#3 ")'k% )K ! "^" I$M(2S ) I%9 & ") (2L 9 nhanh hdn. %-' >O "c 5e & &> ! _#" A ) =)%9 I "NG ") d ! (2S ) A U" R. &^ !. )'k% =) % Ia( A ' IL% B; (g “@(#) ”( ; &^ 5) ; &^ 3:?„ ()'+( !f ")m Rg (2r ! (9 "NG ), ! 4%56 ")} F>3: #ifndef FOO_HH #define FOO_HH // )7 ‚ "'@% 4%56 =) % "c #endif ; &^ 4: P ! IG3 !%: R. &^ ! A : ! & //Không A- ". F> B)Y ! 9 ()g" )%* :
('O*( A@% ) :
#include <../include/fnutt.h> #include <sys/socket.h> ; &^ 5 :/$( )K ! ")'k% "^" I$ AC )+ 2G 4%56 ()% )> ) static const char* sccsid = "@(#) Exception.cpp, rev. A, Copyright Ellemtel Utvecklings AB 1991"; ; &^ 6: {%56 ")} F>3 ")3 5 = PackableString: // file: PackableString.h #ifndef PACKABLESTRING_H #define PACKABLESTRING_H #include "String.h"
#include "Packable.h" // It is not necessary to extern-declare class Buffer when // each pointer declaration specifies the keyword class as shown below. // An explicit extern-declaration makes the code easier to // understand. extern class Buffer; class PackableString : public String, public Packable { public: PackableString( const String& s ); class Buffer* put( class Buffer* outbuffer ); // ... }; #endif ; &^ 7:{%56 ()% )> ) ")3 5 = PackableString : // PackableString.cpp #include "PackableString.h" // To be able to use Buffer-instances, Buffer.h MUST be included. #include "Buffer.h" Buffer* PackableString::put( Buffer* outbuffer ) { // ... }
…D # (9 : '% (a" 10: P A ) &G ) ")3 ), ! 5 = (3> "^"M B%C' 5%*( B9M B%C' A ) !)oGM)>8 M)K ! F> ), ! I%H (23 ! 8$( () F%* 5 = (%- (@ Ac 5> unique ")3 () F%* . '% (a" 11: 9 "NG ), ! I%H M ), ! )K !M ), ! )>8 A U" Ia( A ' F % 8$( "), "#% () : !.
'% (a" 12: 9 "NG ), ! B%C' &, 5%*' (2P' ( U ! M ), ! " ' (27"MB%C' A ) !)oGMB%C' 5%*( B9 A U" Ia( A ' F % "), "#% hoa. '% (a" 13: 23 ! ), ! (9 )%-' )d 8$( (P M ), ! (P A U" F%H( 5%- )G' F> 8k% (P =) % Ia( A ' F % 8$( "), "#% F%H( )3G. '% (a" 14: Không A U" R. &^ ! (P A ) &G ) F % 8$( )GO )G% A : ! !J") & %(‘_’ hay ’__’). '% (a" 15: /$( (9 (#") I%*( F % (%- (@ "NG c 5> 8$( & ' !J") & %(‘_’). '% (a" 16: /$( (9 Ia( A ' F % 8$( "), "#% )3G A U" _' ( )%* !GO RG' (%- (@ "NG c. '% (a" 17: /$( (9 Ia( A ' F % 8$( "), "#% () : ! (#") IJ") F % (%- (@ "NG c IL% & '(‘_’). - ". 13: ?)Y ! A U" R. &^ ! ), ! B%C' (9 8> ")i "c B)#" )G' F- ), ! "), )3G F> "), () : !. - ". 14: 9 B)Y ! 9 IG3 !18 ), ! "), F%H( (Ga( 8> B)Y ! A U" ") = )+ chung. - ". 15: )Z (9
), ! I%H 8> "c (; ) ") ( !U% ‚ R. &^ !.
- ". 16: c% !Z ), ! I%H (3> "^" F> ), ! )K ! MB%C' 5%*( B9MB%C' A ) !)oG (23 ! 8$( 5 =.
23 ! ") d ! >O M ()+( 5> `'G (2Z ! AC =)b I%*( !%,G ), ! (P A ) &G ) F> ), ! (9 . 9 5> 8$( =) "NG (P A ) &G ) "#% 8> I%C' () !)oG "NG c./$( (P A ) &G ) IG3 !18 8$( (%(@M8$( (9 F> 8$( )+' (@q()63 ()T (g). %- (@ F> )+' (@ 5> (rO ")Z ./$( )+' (@ ")i A U" R. &^ ! bL% "Y ! "^ 80 xx (V ! `'#( MAC (2# ) _' ! A$( !%,G F % ), ! 80 xx &3 ! :% R. &^ ! F%H(. [. &^ ! )G% & ' !J") & % (‘__’) (23 ! (P A ) &G ) A U" &> ) 2%9 ! I9 (23 ! I%9 & ") R. &^ ! ()63 ANSI- ")'† . ), ! & ' !J") & % (‘_’) () : ! A U" R. &^ ! (23 ! ), ! (9 "NG ), ! )>8 () F%* q ) 5> “_main” F>”_exit”)D C (2# ) Rg _' ! A$( MB)Y ! A U" Ia( A ' (P A ) &G ) F % 8$( & ' !J"). /$( `'% (a" "); ) OH' 5> Am( 8$( (9 8> không A U" _#" A ) 2w 2> ! 5> 8$( "#") Am( (9 (1% (*./$( "#% (9 &>% ()Y ! () : ! (@( )d (9 !a M(9 B)c )%C'MRg "a( _‡ "h ! 5> F A- " =) % _68 _‡(. ), ! "), F%H( (a( "c ()C 5'Y 5'Y !bO Rg )%C' 5 8. ), ! I%H (3> "^",n), ! )>8 M ), ! )K ! =) % 5> 8$( "#% (9 AN &>% AC (2# ) Rg _' ! A$( ) ! B)Y ! `'# &>%. c 2 ( )%-' 5 = "c ()C (+ &^ ! (23 ! () F%* F> !% R. (23 ! 8$( =23ˆ6"( "c )> ! !> 5 = M&3 F+O ()+( 5> `'G (2Z ! AC Am( (9 AC (2# ) Rg _' ! A$( _ O 2G./$( "#") AC !f ")m Rg _' ! A$( 5> =) % "c 8$( `'% (a" !)%98 B)a" ")3 F%*" !# (9 A@% F % ), ! A@% ( U ! (3> "^" "c ()C () O A U". )63 "#") >O ), ! 5 = (P (23 ! () F%* "c ()C A U" R. &^ ! "r ! 8$( 57".
9 "NG ), ! B%C' RG' AbO =) % "c (%- (@: • 9 B%C'(classes, typedefs, enums, structs, unions, etc). • ), ! )K ! F> ), ! I%H (3> "^". • ), ! (9 )>8qB)Y ! 5> "#" )>8 ()> ) F%9 ) • #" ")i () (#define) ), ! I%H (o ) (23 ! 8$( 5 = 9 A U" R. &^ ! ()GO FS ), ! )K ! MI%H (3> "^" MB%C' &, 5%*' 5%*( B9 F> A ) !)oG. ; &^ 8: )Z (9 : int groupID; // instead of grpID int nameLength; // instead of namLn PrinterStatus resetPrinter; // instead of rstprt ; &^ 9: ), ! (9 8d )1: void termProcess(); // Terminate process or // terminal process? ; &^ 10: 9 F % ), ! B; (g R@ "c ()C 5> !'O9 )b 5k% FS B)c A ) F : int I0 = 13; // Names with digits can be int IO = I0; // difficult to read.
; &^ 11: ) !)oG 5 = (23 ! 5 = () F%* : class Emc2Class { public: Emc2Class(); // Default constructor // ... private: int id; // ... };
; &^ 12:/$( "#") AC (2# ) "#" )>8 F> "#" 5 = (3> "^": // )GO FS B)G% I#3: void Emc2_myFunc1(); void Emc2_myFunc2(); class Emc2MyClass { /* ... */ }; // c% !Z ), ! )>8 R. &^ ! 5 = (2P' ( U !: class Emc2
{ public: static void myFunc1(); static void myFunc2(); class MyClass { /* ... */ }; private: virtual dummy() = 0; // Trick to make the class abstract }; // Now, functions and classes may be accessed by using the scope-operator: Emc2::myFunc1(); Emc2::myFunc2(); Emc2::MyClass myObject;
‰D<)3 ! "#")(Style) 6.1.Nh, ! 5 =(Classes)
'% (a" 18: ), ! ()> ) ph n protected ,public MF> private (23 ! 8$( "5GRR A U" B)G% I#3 ()63 ()T (g AcqA ' (%9 5> public AH protected F> "'@% "r ! 5> private). '% (a" 19: Không 8$( )>8 ()> ) F%9 >3 A U" A ) !)oG (23 ! 8$( 5 =. %*" Am( B)G% I#3 public A ' (%9 M8Z% ()T `'G (b8 IL% ! :% &r ! A U" (+= )U= (23 ! A%C8 Ia( A ' "NG F%*" B)G% I#3 5 =. <) protected "c 5e "h ! A U" `'G (b8 IL% ! :% ()%H( BH B)% _68 _‡( (; ) BH ()PG "NG 8$( 5 =D<) private ")TG ), ! ")% (%H( () : ! ;( `'G (b8 )d . ), ! )>8 ()> ) F%9 A U" A ) !)oG (23 ! 8$( 5 = (g A$ ! (2L ()> ) )>8 inline DQ:% A ) !)oG 5 = 5> B‡8 ")m( ")e F> !m= )%-' B)c B)f AC AZ" B)% A ) !)oG ")7 ! (23 ! Ac. > ! U" 5J% B)% B)G% I#3 ), ! L !3>% A ) !)oG 5 = ()S c Re (2L ()> ) ), ! )>8 ()Y ! () : !. ; &^ 12:/$( A ) !)oG 5 = ()63 `'% (a" "NG =)3 ! "#") : class String : private Object { public: String(); // Default constructor String( const String& s ); // Copy constructor
unsigned length() const; // ... protected: int checkIndex( unsigned index ) const; // ... private: unsigned noOfChars; // ... }; ; &^ 13:?)Y ! A ) !)oG )>8 ()> ) F%9 (23 ! B)G% I#3 5 =: // )GO FS F%H( ) RG': class String { public: int length() const // KHÔNG !! { return len; } // ... private: int len; }; // 9 B)G% I#3 ) RG': class String { public: int length() const; // ... private: int len; }; inline int String::length() const { return len; }
6.2. ), ! )>m(Functions) - ". 17:
Kh% B)G% I#3 8$( )>8 ()S & ' !3m" A ' (%9 F> A@% R@ A ' (%9 q H' "c) =) % A U" F%H( (29 "r ! 8$( &ƒ ! F % (9 )>8. H' B)3 ! (2@ ! ")3 =)‡= ()S & ' !3m" Ac ! F> "#" A@% R@ B)#" "h ! "r ! 8$( &ƒ !. #") B)#" 8k% A@% R@ A U" F%H( 8$( &ƒ !. - ". 18: 23 ! A ) !)oG )>8 ()S B%C' (2 F- =) % =) % F%H( L 8$( &ƒ ! "#") I%*(. - ". 19: Q'Y 5'Y F%H( & ' !3m" I9 (2#% !GO RG' (9 )>8. ; &^ 14:W ' !3m" (2#% 5'Y 5'Y F%H( !GO RG' (9 )>8: Void foo (); // ? Š ‹!! void fooqŒ• •• Ž ! ; &^ 15: #") B)G% I#3 A7 ! F> RG% ), ! A@% R@ (23 ! A ) !)oG )>8: // 7 !: int myComplicatedFunction( unsigned unsignedValue, int intValue, char* charPointerValue, int* intPointerValue, myClass* myClassPointerValue, unsigned* unsignedPointerValue ); // SAI: int myComplicatedFunction( unsigned unsignedValue, int intValue, char* charPointerValue, int* intPointerValue, myClass* myClassPointerValue, unsigned* unsignedPointerValue );
6.3D?)@% 5* ) A%-' B)%C : - ". 20: ), ! B)@% 5* ) A%-' B)%C ) if , else , for , while ,do… 9 A U" ()63 RG' IL% 8$( ! " !GO " B)% ")7 ! (2@ !. ?)% 8> B)Y ! "c 8$( B)@% ()S (G "c ()C & &> ! Am( RG' c 8$( & ' ") 8 =)†O F> A%-' >O Re & Rg )%C' 5 8 B)% AZ" 80 F> "c ()C & AH ") d ! (2S ) I RG% 8> (G B)c () O A U".
; &^ 16:
' (27" B)@% 5* ) B)% B)Y ! "c 5* ) I9 (23 !:
// No block at all - No! while ( /* Something */ ); // Empty block - better! while ( /* Something */ )
AH
{ // Empty ! }
6.4. 3 (2E F> ()G8 ")%H': - ". 21: 3# (. (2E (*) F> (3# (. A G ")i (&) 9 Am( !GO RG' B%C' (9 (23 ! B)G% I#3 F> A ) !)oG. #" B; (g ‘ * ’ F> ‘ & ’ 9 Am( !GO RG' B%C' "NG I%H ()GO FS RG' (9 I%H AC ) 8J ) 2K ! ")7 ! 5> =) "NG B%C' A ) !)oGD )GO FS B)G% I#3 2K ! *i 5> B%C' int ()S B)G% I#3 int*. 23 ! ), ! "b' B)G% I#3 B%C' "NG I%H ()S =) % B)G% I#3 (3# (. (23 ! !GO RG' (9 I%H AC 5>8 !% 8 _#" R' ( 5k%. ; &^ 16: ?)G% I#3 F % ‘ & ’ F> ‘ * ’ : char* Object::asString() { // Something }; char* userName = 0; int sfBook = 42;int& anIntRef = sfBook; ; &^ 17:?)G% I#3 F>% I%H (23 ! "b' 5* ) "c ( * ): ••?)Y ! 9 B)G% I#3 char* i,j; // i is declared pointer to char, while j is declared char
7.L p(Class) 7.1/ Quy-n Truy C+p ( Right Access) '% (a" 20:
- Không bao gi: dùng identifier public hay protected cho các d, li*u thành ph n ( member data) trong m$t l p. - Vi*c s. d^ng biHn toàn c^c (public variable) không A Uc khuyHnh khích b:i vì nh,ng lí do sau Aây: 1. Vi*c s. d^ng biHn toàn c^c se vi phJm m$t trong nh,ng nguyên tac cd b n cNa l+p trình h ng A@i t Ung – Aó là tính bao Aóng ( encapsulation). Ví d^, nHu có m$t l p có kiCu là BankAccount, trong Aó account_balance là m$t biHn toàn c^c ( public variable), thì giá tr cNa biHn này có thC b thay AVi bLi b t cT sg truy c+p nào tP bên ngoài. Tuy nhiên, nHu biHn A Uc khai bò là private, giá tr cNa nó chi có thC b thay AVi bLi nh,ng hàm thành ph n trong l p Aó 2. B t cT hàm nào trong m$t ch dng trình hng có thC thay AVi giá tr cNa public data. Vi*c này có thê gây ra nh,ng lki mà ta khó có thC xác A nh A Uc. 3. Khi mà m$t public data không A Uc s. d^ng, thì vi*c thay AVi d, li*u cNa biHn này se không làm cho các class s. d^ng class này ph i thay AVi lJi code cNa mình. Tóm lJi thì ta nên hi*n thgc m$t l p sao cho mZi sg thay AVi trong sg hi*n thgc cNa l p này se không làm thay AVi nh,ng l p s. d^ng nó. Vi*c s. d^ng nh,ng biHn protected trong m$t class chng không nên A Uc khuyHn khích, bLi vì nh,ng biHn protected này se trL nên visible A@i v i nh,ng l p d n xu t ( derived class) cNa nó. Tên cNa kiCu ( type) và biHn ( variable) trong l p cd sL ( base class) không nên thay AVi bLi vì nh,ng l p d n xu t ( derived class) có thC ph^ thu$c vào chúng. NHu trong m$ tr :ng hUp nào Aó, l p d n xu t truy xu t AHn data trong l p cd sL ( base class), m$t gi i pháp là viHt m$t hàm protected trong base class tr v- nh,ng private data trong base class. HJn chH s. d^ng struct bLi vì nó chi chTa public data. ; &^ 18:D i Aây là cách AC Aóng gói d, li*u ( encapsulate) sao cho có thê thay AVi nó sau này // Original class: class Symbol {}; class OldSymbol : public Symbol {}; class Priority { public: // returns pd int priority(); // returns symbol class Symbol* getSymbol() const; // ... private: int pd; OldSymbol symbol; };
// L p A Uc chinh s.a:
// L+p trình viên chZn thay AVi private data tP kiCu nguyên sang enum. M$t user cNa class ‘Priority’ không ph i thay AVi code, bLi vì giá tr tr v- enum tP hàm thành ph n ( member function) priority()A Uc tg A$ng chuyCn sang kiCu nguyên. class Symbol {}; class NewSymbol : public Symbol {}; enum Priority { low, high, urgent }; class Priority { public: // Interface intact through implicit cast, returns priority_data Priority priority(); // Interface intact, object of new subclass to symbol returned class Symbol* getSymbol() const; // ... private: Priority priority_data; // New representation/name of internal data NewSymbol symbol; };
7.2.Hàm Inline : - ". 21: Access functions nên là inline. - ". 22: Nh,ng hàm chuyCn tiHp nên inline. - ". 23: Constructor và destructor không nên là inline. Lý do AC khai báo m$t hàm là inline là AC tfng t@c A$ thgc thi cNa nó. Nh,ng hàm nhE, chnng hJn nh access function, tr v- giá tr cNa m$t thành ph n ( member) cNa m$t class và nh,ng hàm forwarding se thgc thi m$t hàm khác ( chng là hàm inline). Vi*c s. d^ng hàm inline Aúng chk se d n AHn vi*c gi m kích th c cNa code. Chú ý: - Nh,ng hàm mà gZi hàm inline khác thì se trL nên phTc tJp cho trình biên d ch trong vi*c làm cho chúng inline, mmc dù nh,ng hàm này chi là nh,ng hàm nhE. - ây là v n A- th :ng hay gmp A@i v i constructor và destructor. M$t constructor luôn luôn gZi thgc thi m$t constructor cNa l p cd sL ( base class) và nh,ng d, li*u thành ph n ( member data) tr c khi thgc thi code cNa nó. Nên tránh inline constructor và destructor.
7.3 Friends: - Friends cNa m$t class nên cung c p thêm nh,ng hàm mà A Uc gi, L ngoài class. - Nh,ng operation trên m$t class Aôi lúc A Uc cung c p bLi m$t t+p hUp cNa class và hàm. - M$t friend không ph i là m$t member cNa m$t class và A Uc phép truy c+p AHn nonpublic members cNa class. Friends cung c p m$t cách AC có thC “Ai ngõ sau” A@i v i sg bao Aóng d, li*u ( data encapsulation) cNa m$t class. M$t friend class A Uc s. d^ng AC cung c p hàm yêu c u d, li*u hdn là nh,ng hàm c n thiHt bLi class nh thông th :ng. Gi s. có m$t class list c n m$t con trE ( pointer) AC duy*t t t c các element cNa list. Con trE này thi không c n thiHt cho các operation khác trên list. Trong m$t vài tr :ng hUp, chnng hJn nh c n tìm ph n t. nhE nh t cNa list, thì thay vì tJo m$t iteratE, chúng ta chTa con trE trE AHn các element cNa list. M$t v n A- v i gi i pháp này là class iterator không thC truy xu t AHn c u trúc d, li*u A Uc s. d^ng AC represent list ( bLi vì chúng ta Aã khuyHnh khích dùng private date). BKng cách khai báo iterator class nh là m$t friend class, v n A- này có thC A Uc gi i quyHt mà không có vi phJm tính bao Aóng cNa d, li*u ( data encapsulation). S. d^ng friend thì t@t nHu A Uc s. d^ng Aúng lúc.
7.4 Hàm hKng thành viên: '% (a" 21: - M$t hàm thành ph n mà không thay AVi biHn cNa m$t object thì A Uc khai báo là const. '% (a" 22: - NHu hành A$ng cNa m$t object ph^ thu$c vào data bên ngoài objct thì data này không nên A Uc chinh s.a ( modified) bLi hàm thành ph n const. - Hàm thành ph n ( member function) A Uc khai báo là const không A Uc chinh s.a nh,ng d, li*u thành ph n và chi nh,ng hàm A Uc gZi trên nh,ng A@i t Ung hKng ( const object). ( Nh,ng object nh v+y coi nh vô d^ng ( unusable ) nHu không có const method. Vi*c khai báo const A m b o cho object không b chinh s.a ( modified). M$t thu+n lUi l n A Uc cung c p bLi C++ là kh nfng overload function A@i v i “tính ch t hang” ( const-ness) cNa chúng. ( Hai hàm thành ph n có thC có cùng tên , trong Aó m$t hàm là const và hàm còn lJi thì không). - HoJt A$ng cNa m$t object có thC b nh h Lng bLi d, li*u bên ngoài object. Nh,ng d, li*u nh v+y không nên A Uc chinh s.a bLi m$t const member function.
Ví d^ 19: const-declared access functions to internal data in a class : class SpecialAccount : public Account { public:
int insertMoney(); // int getAmountOfMoney(); No! Forbids ANY constant object to // access the amount of money. int getAmountOfMoney() const; // Better! // ... private: int moneyAmount; }; Ví d^ 20: Overloading an operator/function with respect to const-ness #include
#include <string.h> static unsigned const cSize = 1024; class InternalData {}; class Buffer { public: Buffer( char* cp ); // Inline functions in this class are written compactly so the example // may fit on one page. THIS is NOT to be done in practice // A. non-const member functions: result is an lvalue char& operator[]( unsigned index ) { return buffer[index]; } InternalData& get() { return data; } // B. const member functions: result is not an lvalue char operator[]( unsigned index ) const { return buffer[index]; } const InternalData& get() const { return data; } private: char buffer[cSize]; InternalData data; }; inline Buffer::Buffer( char* cp ) { strncpy( buffer , cp , sizeof( buffer ) ); } main() { const Buffer cfoo = "peter";// This is a constant buffer Buffer foo = "mary";// This buffer can change
foo[2]='c';// calls char& Buffer::operator[](unsigned) cfoo[2] = 'c' // ERROR: cfoo[2] is not an lvalue. // cfoo[2] means that Buffer::operator[](unsigned) const is called. cout << cfoo[2] << ":" << foo[2] << endl; // OK! Only rvalues are needed foo.get() = cfoo.get(); cfoo.get() = foo.get(); // ERROR: cfoo.get() is not an lvalue }
7.5 Constructor và Destructor: '% (a" 23: - M$t class mà s. d^ng “new” AC c p phát m$t thgc thC (instance) A Uc qu n lý bLi class, ph i A nh nghoa m$t constructor. '% (a" 24: - T t c các class A Uc s. d^ng nh m$t base-class ( có hàm o – virtual machine), ph i A nh nghoa m$t virtual destructor. - ". 24: - Tránh s. d^ng A@i t Ung toàn c^c ( global object) trong constructor và destructor. - M$t copy cNa constructor A Uc khuyHn khích AC tr :ng hUp m$t object A Uc khLi tJo s. d^ng m$t object cùng kiCu. NHu m$t object qu n lý sg c p phát ( allocation) và hu• ( deallocation) m$t object trên vùng heap (A@i t Ung qu n lý s. d^ng m$t con trE trE AHn object A Uc tJo bLi constructor cNa class), chi nh,ng giá tr cNa con trE se A Uc copy. i-u này có thC d n AHn sg hai invocation cNa destructor cho cùng m$t object ( trên vùng heap), se d n AHn run-time error. - V n A- t dng tg x y ra A@i v i toán t. gán (“=”) - NHu m$t class, có m$t hàm o nh ng không có destructor o, A Uc s. d^ng, there may be a surprise if nh,ng con trE trE AHn class A Uc s. d^ng. NHu m$t con trE nh v+y A Uc gán cho m$t thgc thC (instance) cNa m$t l p d n xu t và nHu delete A Uc s. d^ng trên object này, chi destructor cNa base class A Uc thgc thi. NHu ch dng trình ph^ thu$c vào sg thgc thi destructor cNa l p d n xu t, ch dng trình se fail. - Liên quan AHn sg khLi tJo cNa nh,ng object A Uc c p ph t tonh ( statically allocated object), không có gì chac chan rKng nh,ng A@i t Ung tonh (static object) khác se A Uc khLi tJo ( ví d^, global object). BLi vì thT tg khLi tJo cNa object tonh ( cái mà A Uc A nh nghoa trong nh,ng Adn v biên d ch khác nhau), thì không A Uc A nh nghoa trong A nh nghoa cNa ngôn ng,. - BJn ph i biHt nh,ng gì bJn Aang làm nHu bJn gZi m$t hàm o tP m$t constructor trong m$t class. NHu m$t hàm o trong m$t l p d n xu t A Uc overridden, A nh nghoa ban A u (original definition) trong base class se v n A Uc thgc thi bLi constructor cNa base class. Override, then, không luôn luôn work khi gZi hàm o trong constructor . Xem VD 30. NgoJi l* A@i vLi Rule 24:
-
ôi khi chúng ta mu@n nh,ng object trong m$t class chia se dg li*u. Trong tr :ng hUp nh v+y, không c n thiHt ph i A nh nghoa m$t copy constructor.
Ví d^ 21:M$t A nh nghoa l p “nguy hiCm” không có m$t copy contructor : #include <string.h> class String { public: String( const char* cp = ""); // Constructor ~String(); // Destructor // ... private: char* sp; // ... }; String::String(const char* cp) : sp( new char[strlen(cp)] ) { strcpy(sp,cp); } String::~String() // Destructor { delete sp; }
// Constructor
// "Dangerous" String class void main() { String w1; String w2 = w1; // WARNING: IN A BITWISE COPY OF w1::sp, // THE DESTRUCTOR FOR W1::SP WILL BE CALLED TWICE: // FIRST, WHEN w1 IS DESTROYED; AGAIN, WHEN w2 IS DESTROYED. }
Ví d^ 22:L p “an toàn” có copy contructor và contructor mmc A nh : #include <string.h> class String
{ public: String( const char* cp = ""); // Constructor String( const String& sp ); // Copy constructor ~String(); // Destructor // ... private: char* sp; // ... }; String::String( const char* cp ) : sp( new char[strlen(cp)] ) // Constructor { strcpy(sp,cp); } String::String( const String& stringA ) : sp( new char[strlen(stringA.sp)] ) { strcpy(sp,stringA.sp); } String::~String() // Destructor { delete sp; } // "Safe" String class void main() { String w1; String w2 = w1; // SAFE COPY: String::String( const String& ) CALLED. }
Ví d^ 23:
nh nghoa l p không có virtual destructors :
class Fruit { public: ~Fruit(); // ... };
// Forgot to make destructor virtual!!
class Apple : public Fruit { public: ~Apple(); // Destructor
// ... }; // "Dangerous" usage of pointer to base class class FruitBasket { public: FruitBasket(); // Create FruitBasket ~FruitBasket();// Delete all fruits// ... void add(Fruit*); // Add instance allocated on the free store // ... private: Fruit* storage[42]; // Max 42 fruits stored int numberOfStoredFruits; }; void FruitBasket::add(Fruit* fp) { // Store pointer to fruit storage[numberOfStoredFruits++] = fp; } FruitBasket::FruitBasket() : numberOfStoredFruits(0) { } FruitBasket::~FruitBasket() { while (numberOfStoredFruits > 0) { delete storage[--numberOfStoredFruits]; // Only Fruit::~Fruit is called !! } }
Ví d^ 24:M$t cách b o A m rKng m$t A@i t Ung toàn c^c A Uc khLi tJo : // WARNING!!! Mã này không cho ng
ib t
u h c !!!
// PortSetup.hh class PortSetup { public: PortSetup();// Constructor: initializes flag void foo();// Only works correctly if flag is 42 private: int flag;// Always initialized to 42 }; extern PortSetup portSetup; // Must be initialized before use // Create one instance of portSetupInit in each translation unit // The constructor for portSetupInit will be called once for each // translation unit. It initializes portSetup by using the placement // syntax for the "new" operator. static class PortSetupInit { public: PortSetupInit(); // Default constructor private: static int isPortSetup; } portSetupInit; // PortSetup.cc #include "PortSetup.hh" #include // ... PortSetupInit::PortSetupInit() // Default constructor { if (!isPortSetup) { new (&portSetup) PortSetup; isPortSetup = 1; } }
Ví d^ 25 : Override of virtual functions does not work in the base class' constructors
class Base { public: Base(); // Default constructor virtual void foo() { cout << "Base::foo" << endl; } // ... }; Base::Base() { foo(); // Base::foo() is ALWAYS called. } // Derived class overrides foo() class Derived : public Base { public: virtual void foo() { cout << "Derived::foo" << endl; } //foo is overridden // ... }; main() { Derived d; // Base::foo() called when the Base-part of // Derived is constructed. }
7.6 Toán t. gán: '% (a" 25: - M$t class s. d^ng “new” AC c p phát m$t thgc thC AgUc qu n lý bLi class, ph i A nh nghoa toán t. gán. '% (a" 26: - M$t toán t. gán thgc hi*n m$t destructive action ph i A Uc b o A m là không có thgc hi*n destructive trên object mà nó Aang tác A$ng. - ". 25: - M$t toán t. gán ph i tr v- tham chiHu hKng ( const reference) AHn A@i t Ung gán (assigning object). - Toán t. gán không A Uc kH thPa nh nh,ng toán t. khác. NHu toán t. gán không A Uc A nh nghoa m$t cách t :ng minh (explicitly), thì m$t toán t. gán khác se A Uc tg A$ng A nh nghoa. Nh,ng toán t. gán nh v+t không thgc hi*n bit-wise copy d, li*u thành ph n; thay vào Aó, toán t. gán (A Uc A nh nghoa) cho mki kiCu d, li*u thành ph n A Uc gZi. Bit-wise copying chi A Uc thgc hi*n A@i v i d, li*u thành ph n có kiCu d, li*u nguyên thu• ( primitive).
- M$t h* qu cNa vi*c này là bit-wise copying A Uc thgc hi*n A@i v i d, li*u thành ph n có kiCu con trE. Vi*c này se d n AHn m$t v n A-: homc là gZi destructor cho A@i t Ung A Uc qu n lý nhi-u l n homc là c@ gang s. d^ng A@i t Ung Aã A Uc hu• ( deallocated object). See Rule 25. - NHu m$t toán t. gán A Uc overload, l+p trình viên ph i A m b o rKng l p cd sL và toán t. gán cNa member chJy. - M$t lki th :ng gmp là gán m$t object cho chính nó. Bình th :ng, destructor m$t thgc thC cái mà A Uc c p phát trên vùng nh heap A Uc gZi tr c khi vi*c gán A Uc thgc thi. NHu m$t object A Uc gán cho chính nó, giá tr cNa biHn thgc thC se b m t bLi vì nó A Uc gán. Vi*c này se dãn AHn run-time errors. If a =a A Uc dò ra, A@i t Ung A Uc gán không thay AVi.
Ví d^ 26: Giá tr tr v- Aúng và không Aúng tP toán t. gán: void MySpecialClass::operator=( const MySpecialClass& msp );
/ Well ...?
MySpecialClass& MySpecialClass::operator=( const MySpecialClass& msp );
// No!
const MySpecialClass& MySpecialClass::operator=( const MySpecialClass& msp );
// Recommended
Ví d^ 27: Definition of a class with an overloaded assignment operator class DangerousBlob { public: const DangerousBlob& operator=( const DangerousBlob& dbr ); // ... private: char* cp; }; // Definition of assignment operator const DangerousBlob& DangerousBlob::operator=( const DangerousBlob& dbr ) { if ( this != &dbr ) // Guard against assigning to the "this" pointer { delete cp; // Disastrous if this == &dbr } // ... }
7.7 Quá t i toán t. - ". 26: - Khi hai toán t. là ng Uc nhau ( ví d^ nh == va !=) thì nên A nh nghoa c hai. - Operator Overloading có mmt thu+n lUi l n b t lUi. M$t thu+n lUi là code s. d^ng class có overloaded operators se d AZc hdn. M$t thu+n lUi khác là ng, nghoa ( semantic) thì Adn gi n và tg nhiên. M$t b t lUi là d b hiCu nh m ý nghoa cNa overloaded operator ( nHu l+p trình viên không s. d^ng nghoa thông th :ng). Ví d^ nh toán t. c$ng thì A Uc A nh nghoa lJi v i ý nghoa là trP và toán t. trP A Uc A nh nghoa lJi v i nghoa là c$ng . - nh nghoa m$t th vi*n class thì gi@ng nh vi*c A nh nghoa m$t ngôn ng,. NHu s. d^ng operator overloading, s. d^ng nó theo l@i hiCu thông th :ng, không s. d^ng nó nHu vi*c này có thC d n AHn hiCu l m.
7.8 Hàm thành ph n tr và kiCu tr v-: '% (a" 27: - M$t public member function không nên tr v- m$t non-const reference homc con trE AHn d, li*u thành ph n. '% (a" 28: - M$t pubic member function không tr lJi m$t non-const reference homc m$t con trE AHn d, li*u bên ngoài cNa object ngoJi trP tr :ng hUp object chia s• d, li*u v i nh,ng A@i t Ung khác. - BKng cách cho phép truy su t trgc tiHp AHn m$t private member data cNa m$t object tP bên ngoài, d, li*u này có thC b thay AVi theo cách mà không Aúng v i ý A nh thiHt kH class cNa ng :i thiHt kH. Vi*c này làm gi m sg tin c+y cNa designer’s code. - M$t tr :ng hUp nguy hiCm n,a là s. d^ng nh,ng con trE trE AHn vùng nh Aã b hu• . Rule 29 và 30 se tránh tr :ng hUp này.
Ví d^ 28: Png bao gi: tr v- m$t tham chiHu không ph i là hKng AHn d, li*u thành viên tP hàm public: class Account { public: Account( int myMoney ) : moneyAmount( myMoney ) {}; const int& getSafeMoney() const { return moneyAmount; } int& getRiskyMoney() const { return moneyAmount; } // ... private: int moneyAmount; };
// No!
Account myAcc(10); // I'm a poor lonesome programmer a long way from home myAcc.getSafeMoney() += 1000000; // Compilation error: assignment to constant myAcc.getRiskyMoney() += 1000000; // myAcc::moneyAmount = 1000010 !!
7.9 KH thPa - ". 27: - Tránh sg thPa kH cho quan h* parts-of ( cái này chi là thành ph n cNa cái kia). - ". 28: - Chi nên cho phép l p d n xu t truy xu t AHn d, li*u cNa l p cd sL bKng cách khai báo protected access function. - M$t lki th :ng gmp n,a là s. d^ng nhi-u l n sg kH thPa cho quan h* parts-of ( khi m$t object chTa m$t vài object khác, nh,ng object này A Uc kH thPa thay vì s. d^ng nh,ng biHn thành ph n. i-u này có thC d n AHn m$t c u trúc class lJ mat và code thì không có kh chuyCn ( flexible) . Trong C++, có thC có m$t s@ l Ung b t k‘ cNa s@ l Ung thgc thC cNa m$t kiCu d, li*u cho s’n; nHu sg kH thPa A Uc s. d^ng, sg kH thPa trgc tiHp tP m$t class chi A Uc s. d^ng m$t l n. - M$t l p d n xu t th :ng c n truy c+p AHn d, li*u thành ph n cNa l p cd sL AC tJo ra m$t hàm thành ph n. Thu+n lUi trong vi*c s. d^ng hàm thành ph n protected là tHn cNa d, li*u cNa l p cd sL không có visible (A Uc nhìn th y) trong l p d n xu t và vì v+y có thC b thay AVi. Nh,ng hàm truy xu t (access function) nên tr lJi giá tr cNa d, li*u thành ph n ( read-online acccess). i-u này A Uc thgc hi*n m$t cách Adn gi n bKng cách khai báo const function cho d, li*u thành ph n.
8 . L p Template: - ". 29: - Không nên c@ gang AC tJo m$t thgc thC cNa m$t template class sN d^ng kiCu mà không A nh nghoa nh,ng hàm thành ph n mà class template yêu c u. - ". 30: - C†n th+n tránh A nh nghoa nhi-u l n ( multiple definition) nh,ng overloaded function cùng v i sg khLi tJo cNa class template. - Trong C++ thì không thC chi rõ yêu c u cho kiCu cNa A@i s@ cNa class template và function template. Vi*c này có nghoa là kiCu thì A Uc chZn bLi user, không tuân theo interface nh yêu c u bLi template. Ví d^, m$t class template yêu c u kiCu A@i s@ có toán t. so sánh A Uc A nh nghoa. - M$t v n A- v i type template có thC n y sinh A@i v i overloaded function. NHu m$t hàm A Uc overload, có thC se có xung A$t nHu kiCu d, li*u thành ph n ( element type) xu t hi*n t :ng minh
trong m$t trong nh,ng s@ Aó. Sau khi khLi tJo, có thC có hai hàm có kiCu nguyên int nh là m$t A@i s@. Trình biên d ch có thC se thông báo lki, nh,ng th+t là nguy hiCm nHu ng :i thiHt kH class không chú ý nó.
Ví d^ 29:V n A- khi s. d^ng kiCu tham s@: template class Conflict { public: void foo( int a ); void foo( ET a ); // What if ET is an int or another integral type? // The compiler will discover this, but ... };
9. Hàm(Functions) 9.1 @i s@ cNa hàm ( function argument) '% (a" 29: - Không s. d^ng A@i s@ cNa hàm mà không chi rõ kiCu d, li*u ( kí hi*u d u ch m l.ng ). '% (a" 30: - Tránh nh,ng hàm có nhi-u A@i s@. '% (a" 31: - NHu m$t hàm chTa m$t con trE trE AHn m$t object (A Uc truy c+p thông qua A@i s@) thì nên khai báo A@i s@ có kiCu con trE. S. d^ng reference argument trong nh,ng tr :ng hUp nh thH này. - ". 31: - S. d^ng tham chiHu hKng ( const reference) ( const &) thay vì gZi-bKng-giá -tr ( call-byvalue), trP khi s. d^ng nh,ng kiCu d, li*u A Uc A nh nghoa tr c hay con trE. - Hàm thông d^ng s. d^ng A@i s@ không chi rõ (unspecified argument) là printf(). Vi*c s. d^ng nh,ng hàm nh v+y thì không nên A Uc khuyHn khích bLi vì vi*c kiCm tra kiCu khac khe trong C++.Trong m$t vài tr :ng hUp thì vi*c s. d^ng A@i s@ không chi rõ (unspecified argument) có thC A Uc thay thH bKng ch1ng hàm( overloading function) homc sN d^ng A@i s@ mmc A nh ( default argument). - Hàm v i m$t danh sách A@i s@ dài thì nhìn có v• phTc tJp, khó AC AZc và khó AC b o trì sau này. BKng cách s. d^ng tham chiHu ( reference) thay vì con trE nh là A@i s@ cNa hàm thì code d AZc hdn. M$t b t lUi là không d dàng th y A Uc hàm nào thay AVi giá tr cNa A@i s@ cNa nó.
- M$t khác bi*t gi,a tham chiHu và con trE là không có tham chiHu null trong ngông ng,, trong khi có null-pointer. i-u này có nghoa là m$t A@i t Ung ph i A Uc c p phát tr c khi truy-n nó AHn hàm. ThuJn lUi L Aây là không c n thiHt kiCm tra sg t1n tJi cNa A@i t Ung trong hàm. - C++ gZi hàm theo kiCu gZi-bKng-tr ( call-by-value). i-u này có nghoa là nh,ng A@i s@ cNa hàm A Uc copy vào stack thông qua vi*c gZi copy constuctor, vi*c này se d n AHn gi m hi*u qu thgc thi nHu nh,ng object Aó là nh,ng object l n. Ngoài ra, destructor se A Uc gZi khi t1n tJi hàm. @i s@ “const & “ có nghoa là chi nh,ng tham chiHu AHn A@i t Ung trong v n A- Aang nói AHn A Uc Amt vào stack ( callby-reference) và trJng thaía cNa object( biHn cNa thgc thC) không thC chinh s.a A Uc .
Ví d^ 30 :Tham chiHu thay vì con trE : // Unnecessarily complicated use of pointers void addOneComplicated( int* integerPointer ) { *integerPointer += 1; } addOneComplicated( &j ); // Write this way instead: void addOneEasy( int& integerReference ) { integerReference += 1; } addOneEasy( i );
Ví d 31 : Different mechanisms for passing arguments // a. A copy of the argument is created on the stack. // The copy constructor is called on entry, // and the destructor is called at exit from the function. // This may lead to very inefficient code. void foo1( String s ); String a; foo1( a ); // call-by-value // b. The actual argument is used by the function // and it can be modified by the function. void foo2( String& s ); String b; foo2( b ); // call-by-reference // c. The actual argument is used by the function // but it cannot be modified by the function.
void foo3( const String& s ); String c; foo3( c ); // call-by-constant-reference // d. A pointer to the actual argument is used by the function. // May lead to messy syntax when the function uses the argument. void foo4( const String* s ); String d; foo4( &d ); // call-by-constant-pointer
9.2 Ch1ng hàm ( Function overloading) - Khi ch1ng hàm thì mZi biHn thC nên có cùng chung m$t ng, nghoa (A Uc s. d^ng cho cùng m$t m^c Aích). - Ch1ng hàm là m$t công c^ng mJnh AC tJo ra m$t hZ nh,ng hàm liên quan v i nhau mà chi khá nhau L kiCu d, li*u cung c p bLi A@i s@. NHu không s. d^ng nó m$t cách hUp lý ( chnng hJn nh nh,ng hàm gi@ng nhau v- tên A Uc dùng cho nh,ng m^c Aíc khác nhau), có thC gây ra sg nh m l n.
Ví d^ 32:Ví d^ cho cách s. d^ng Aúng cNa quá t i hàm: class String { public: // ... int contains( const char c ); int contains( const char* cs ); int contains( const String& s ); // ... };
// // // // //
Used like this: String x = "abc123"; int i = x.contains( 'b' ); int j = x.contains( "bc1" ); int k = x.contains( x );
9.3 @i s@ hình thTc: '% (a" 32: - Tên cNa formal arguments A@i v i m$t hàm A Uc chi rõ và có thC gi@ng nhau trong khai báo hàm v trong A nh nghoa cNa hàm. - Tên cNa formal arguments A Uc chi rõ trong A nh nghoa hàm và trong khai báo hàm trong C++. Cung c p tên cho A@i s@ hàm là m$t ph n cNa function documention. Tên cNa A@i s@ nên ph n ánh A Uc A@i s@ A Uc s. d^ng nh thH nào, gi m A Uc vi*c ph i viêt comment, ví d^, m$t A nh nghoa l p.
Ví d^ 33 : @i s@ hình thTc : int setPoint( int, int ); // No ! int setPoint( int x, int y ); // Good
int setPoint( int x, int y ) { // ... }
9.4 Giá tr và kiCu tr v-: '% (a" 33: - Luôn luôn chi rõ m$t cách t :ng minh kiCu tr v- cNa m$t hàm . '% (a" 34: - M$t public function không nên tr lJi tham chiHu hay con trE AHn biHn c^c b$. - Hàm mà không có chi rõ kiCu tr v- trong khai báo thì se ng m A nh nh+n kiCu tr v- là int. i-u này có thC gây nh m l n, bLi vì compiler se warning là thiHu kiCu tr v-. BLi vì Ai-u này, nh,ng hàm khôgng có tr v- giá tr nào nên chi rõ kiCu tr v- là void. - NHu m$t hàm tr v- tham chiHu homc con trE AHn m$t biHn c^c b$, b$ nh mà nó trE t i se b hu• khi tham chiHu homc con trE A Uc s. d^ng. Trong m$t s@ tr :ng hUp thì Compiler se give a warning cho tr :ng hUp này.
9.5 Hàm inline: '% (a" 35: - Không s. d^ng preprocessE directive #define AC làm cho code hi*u qu hdn, thay vào Aó, s. d^ng inline function. - ". 32: - S. d^ng inline function khi th+t sg c n thiHt. - Inline function có thu+n lUi là nhanh hdn hàm bình th :ng. B t lUi cNa inline function là vi*c hi*n thgc trL nên quá exposed, bLi vì A nh nghoa m$t inline function ph i A Uc Amt trong m$t include file cNa class, trong khi A nh nghoa cNa m$t hàm bình th :ng A Uc Amt trong m$t file riêng bi*t. - KHt qu là nh,ng thay AVi trong s hi*n thgc ( implementation) cNa m$t inline function yêu c u re-compiling khi include file thay AVi. Vi*c này chi Aúng cho nh,n môi tr :ng l+p trình dga trên fiel ( file-based programming enviroment) s. d^ng nh,ng cd chH nh v+y khi make for compilation. - Compiler không bat bu$c ph i make m$t function inline. QuyHt A nh cho v n A- này tu‘ thu$c vào compiler. Nh,ng thông th :ng thì se set m$t compiler flag sao cho compiler give a warning khi nó không make a function line ( trái v i khai báo). “Outlined inlines” có thC d n AHn nh,ng ch dng trình l n và ch+m m$t cách không c n thiHt. - Se là hUp lí nHu tách A nh nghoa cNa inline function ra khEi A nh nghoa cNa class và Amt chúng vào m$t file riêng bi*t.
Ví d^ 34:Hàm inline t@t hdn macro // Ví d có v n v i #define "functions" #define SQUARE(x) ((x)*(x)) int a = 2; int b = SQUARE(a++); // b = (2 * 3) = 6 // Inline functions are safer and easier to use than macros if you // need an ordinary function that would have been unacceptable for // efficiency reasons. // They are also easier to convert to ordinary functions later on. inline int square( int x ) { return ( x * x ); }; int c = 2; int d = square( c++ ); // d = ( 2 * 2 ) = 4
9.6 @i t Ung tJm th:i: - ". 33: - Gi m thiCu s@ object tJm th:i A Uc tJo ra nh là giá tr tr v- tP nh,ng hàm homc nh là nh,ng A@i s@ cNa hàm. - @i t Ung tJm th:i th :ng A Uc tJo ra khi m$t obect A Uc tr v- tP m$t hàm homc khi A@i t :ng A Uc truy-n nh là m$t A@i s@ cNa hàm. Trong c hai tr :ng hUp, m$t constructor cho object A Uc gZi tr c, sau Aó, destructor A Uc gZi. Nh,ng A@i t Ung tJm v i kích th c l n làm cho code kém hi*u qu . Trong m$t vài tr :ng hUp se xu t hi*n lki khi A@i t Ung tJm A Uc tJo. Và m$t Ai-u quan trZng n,a là không nên dùng con trE trE AHn A@i t Ung tJm , bLi vì th:i gian s@n ( lifetime) cNa m$t A@i t :ng tJm thi không xác A nh.( Xem 18.7)
Ví d^ 35 : @i t Ung tJm và m$t cách AC loJi chúng: class BigObject { double big[123456]; }; // Example of a very inefficient function with respect to temporary objects: BigObject slowTransform( BigObject myBO ) { // When entering slowTransform(), myBO is a copy of the function argument // provided by the user. -> A copy constructor for BigObject is executed. // ... Transform myBO in some way return myBO; // Transformed myBO returned to the user }
// When exiting slowTransform(), a copy of myBO is returned to the // user -> copy-constructor for BigObject is executed, again. // Much more efficient solution: BigObject& fastTransform( BigObject& myBO ) { // When entering fastTransform(), myBO is the same object as the function // argument provided by the user. -> No copy-constructor is executed. // Transform myBO in some way return myBO; // Transformed myBO is returned to the user. } // When exiting fastTransform(), the very same myBO is returned // to the user. -> No copy constructor executed. void main() { BigObject BO; BO = slowTransform( BO ); BO = fastTransform( BO ); // Same syntax as slowTransform() !! }
9.7 TVng quan: - ". 34: - Tránh nh,ng hàm dài và phTc tJp - Nh,ng b t lUi cNa m$t hàm dài: 1. NHu m$t hàm quá dài thì se khó AC hiCu khi AZc. 2. Trong tr :ng hUp có lki trong m$t hàm r t dài thì se khó AC có thC xác A nh lki và “undo” tr c khi report the error to the calling function. BKng cách s. d^ng nh,ng hàm ngan thì nh,ng lki này có thC d dàng xác A nh A Uc. 3. Nh,ng hàm phTc tJp thì khó AC test. NHu m$t hàm chTa AHn 15 câu l*nh if l1ng nhau thì se có 2^15 = 32768 nhánh khác nhau AC kiCm tra trong m$t hàm.
10. HKng (Constant) '% (a" 36: Constant nên A Uc A nh nghoa s. d^ng constant homc enum, thay vì # define. '% (a" 37:
Tránh s. d^ng nh,ng giá tr s@ (numeric value) trong code. Thay vào Aó nHn s. d^ng symbol value. B$ ti-n x. lý ( preprocessor) thgc hi*n sg thay thH cho nh,ng macro trong source code, r1i sau Aó source code A Uc compile. Vi*c này gây ra m$t s@ h+u qu không mong mu@n. Ví d^, nHu m$t hKng s@ A Uc A nh nghoa dùng #define, tên cNa hKng không A Uc nh+n ra trong nhi-u trình gX r@i ( debugger). NHu hKng A Uc thay thH bLi m$t expression, thì expession này có thC AuUc tính toán khác nhau cho nh,ng l n khLi tJo khác nhau,tu‘ thu$c vào t m vgc ( scope) cNa tên biHn. Numerical value trong code ( th :ng A Uc gZi là “Magic Numbers”) nên tránh s. d^ng bLi vì nó có thC gây ra nh,ng khó khfn nHu chúng ta c n thay AVi giá tr cNa chúng. M$t l Ung l n code có thC ph^ thu$c vào m$t giá tr (giá tr này không bao gi: thay AVi), giá tr này có thC A Uc s. d^ng tJi nhi-u v trí khác nhau trong code ( se khó khfn AC xác A nh v trí cNa t t c chúng), và nh,ng giá tr nh v+y hiHm khi anonymous ( có thC x y ra tr :ng hUp là mki s@ ‘2’ trong code không nh t thiHt ph i A Uc thay thH bLi t t c các s@ ‘3’).
Ví d^ 36:Nhi-u cách khác nhau AC khai báo hKng : // Constants using macros #define BUFSIZE 7 // No type checking // Constants using const const int bufSize = 7; // Type checking takes place // Constants using enums enum SIZE { BufSize = 7 }; // Type checking takes place
11. BiHn(Variable) '% (a" 38: BiHn nên A Uc khai báo v i t m vgc nhE nh t có thC. '% (a" 39: Mki biHn A Uc khai báo bKng m$t dòng riêng bi*t. '% (a" 40: Mki biHn A Uc khai báo nên A Uc khLi tJo m$t giá tr nào Aó tr
c khi nó A Uc s. d^ng.
'% (a" 41: NHu có thC thì s. d^ng khLi tJo ( initializatio) thay vì phép gán (assignment).
M$t biHn nên A Uc khai báo v i t m vgc nhE nh t có thC AC có thê nâng cao tính d AZc cNa code, và AC cho biHn không A Uc c p phát không c n thiHt. Khi m$t biHn A Uc khai báo tJi A u cNa m$t hàm A Uc s. d^ng L m$t ndi nào Aó trong code, thì se không de dàn AC biHt trgc tiHp kiCu cNa biHn Aó. Ngoài ra, còn có m$t nguy cd n,a là nh,ng biHn nh v+y thì tình c: b †n nHu nó là biHn c^c b$, có cùng tên, A Uc khai báo L m$t kh@i bên trong ( internal block). M$t biHn ph i A Uc khLi tJo tr c khi s. d^ng. Bình th :ng thì trinh biên d ch se c nh báo nHu m$t biHn ch a A Uc A nh nghoa. Nh,ng chng nên c†n th+n trong nh,ng tr :ng hUp nh v+y bLi vì sg c†n th+n v n không thPa. Thgc thC cNa m$t l p th :n A Uc khLi tJo nHu không có A@i s@ A Uc cung c p trong ph n khai báo ( empty constructor se A Uc gZi). C khai báo m$t biHn mà A Uc khLi tJo trong m$t file khác, the keyword extern A Uc s. d^ng. BKng cách khLi tJo m$t biHn tr c khi s. d^ng, thay vì gán giá tr cho chúng tr c khi chúng A Uc s. d^ng, code se hi*u qu hdn bLi vì không có A@i t Ung tJm A Uc tJo ra trong sg khLi tJo. @i v i nh,ng object chTa m$t l Ung l n d, li*u, vi*c này có thC giúp nâng cao Aáng kC t@c A$ cNa ch dng trình. Chú ý: Trong m$t s@ tr :ng hUp, m$t biHn A Uc gánn giá tr cNa m$t biCu thTc phTc tJp ;lúc Aó se không c n thiHt khLi tJo giá tr ban A u cho biHn. Xem VD 37
Ví d^ 37:KhLi tJo thay vì gán: //Không nên làm Ai-u này! //int i; //... 1022 lines of code //i = 10; int j = 10;// Better class Special//Array of this class is used to initialize{// MyClass::complicated public: Special(); // Default constructorint isValid() const; int value() const; }; const int Magic = 1066; Special specialInit[Magic]; class MyClass { public: MyClass( const char* init ); // Constructor // ... private: String privateString; int complicated; }; // Do not do this! Inefficient code. // Empty constructor + assignment operator called for privateString
// // MyClass::MyClass( const char* init ) // { // privateString = init; // ... // } MyClass::MyClass( const char* init ) : privateString( init ) // Better { // Special case - complicated expression for( int i = 0; i < Magic; i++ )// No! You should enclose "for" if ( specialInit[i].isValid() )// loops in braces! See Rec. 25! { complicated = specialInit[i].value(); break; } }
12. Con trE và tham chiHu: '% (ac 42: Không so sánh con trE NULL homc gán NULL cho m$t con trE, thay vì v+y s. d^ng 0. - ". 35: Con trE trE AHn con trE nên tránh nHu có thC A Uc. - ". 36: S. d^ng typedef AC Adn gi m syntax cNa prEgam khi khai báo m$t con trE hàm. Trong ANSI-C standard, NULL A Uc A nh nghoa homc là (void *) 0 homc 0. NHu A nh nghoa này v n còn Aúng trong ANSI-C++ thì se n y sinh ra v n A-. NHu NULL A Uc A nh nghoa là kiCu “void*), nó không thC A Uc gán cho b t cT con trE nào mà không ép kiCu m$t cách t :ng minh (explicit type conversion). Vì lí do này, nên so sánh v i 0 ít nh t cho AHn khi ANSI-C++ committee A a ra quyHt A nh. Con trE trE AHn con trE thì th :ng không A Uc s. d^ng. Thay vì v+y, m$t l p nên A Uc khai báo, trong Aó có chTa m$t biHn thành ph n là kiCu con trE. Vi*c này nâng cao tính d AZc cNa code và khuyHnh khích trPu t Ung hoá d, li*u ( data abstraction). BKn cách c i thi*n tinh d AZc cNa code, xác xu t AC m$t ch dng trình chJy Aúng se A Uc nâng cao hdn. M$t hàm thay AVi giá tr cNa con trE A Uc cung c p d tham chiHu AHn con trE ( e.g. char & c) .
i dJng A@i s@, nên khai báo A@i s@ có
Typedef là m$t cách hay AC giúp code d b o trì và kh chuyCn ( portable). Xem 18.1, Port.Rec.1. M$t lý do khác AC s. d^ng typedef là tính d dZc cNa code A Uc c i thi*n. Con trE hàm có thC A Uc s. d^ng nh hàm bình th :ng; chúng không c n dereferenced.
Ví d^ 38:So sánh sg khác bi*t cNa nh,ng con trE: char* sp = new char[100]; if ( !sp ) cout << "New failed!" << endl; // No! if ( sp == 0 ) cout << "New failed!" << endl; // Best if ( sp == NULL ) cout << "New failed!" << endl; // ERROR sometimes !!!
Ví d^ 39:Con trE trE t i con trE là không c n thiHt: #include void print_mij(int** m, int dim1, int dim2) { for (int i = 0; i < dim1; i++) { for (int j = 0; j < dim2; j++ ) cout << " " << ((int*)m)[i*dim2+j]; cout << endl; } } // Có th c vi t l i là: class Int_Matrix { public: Int_Matrix(int dim1, int dim2); int value(int,int) const; int dim1() const; int dim2() const; // .. }; void print_Mij(Int_Matrix m) { for (int i = 0; i < m.dim1(); i++) { for (int j = 0; j < m.dim2(); j++ ) cout << " " << m.value(i,j); cout << endl; } }
Ví d^ 40:Nh,ng khai báo phTc tJp: // func1 là m t hàm: int -> (function : const char* -> int) // t c là hàm có m t i s c a ki u int và ki u tr v // là m t con tr n hàm có m t i s ki u const char* // và tr v ki u int
int (*func1(int))(const char*); // func1 of the same type as func2 typedef int FTYPE(const char*); FTYPE* func2(int); int (*(*func1p)(int))(const char*) = func2; // Realistic example from signal.h void (*signal(int,void (*)(int)))(int);
Ví d^ 41:Cú pháp Adn gi n nh,ng hàm con trE s. d^ng m$t typedef #include <math.h> // Ordinary messy way of declaring pointers to functions: // double ( *mathFunc ) ( double ) = sqrt; // With a typedef, life is filled with happiness (chinese proverb): typedef double MathFuncType( double ); MathFuncType* mathFunc = sqrt; void main() { // You can invoke the funktion in an easy or complicated way double returnValue1 = mathFunc( 23.0 ); // Easy way double returnValue2 = ( *mathFunc )( 23.0 ); // No! Correct, but complicated }
13 . Ép kiCu: '% (a" 43: Tránh s. d^ng ép kiCu t :ng minh (explicit type conversion) ( casts). '% (a" 44: Không viHt code ph^ thu$c vào nh,ng hàm sN d^ng ép kiCu không t :ng minh. '% (a" 45:
Không bao gi: chuyCn con trE trE AHn A@i t Ung cNa l p d n xu t thành con trE trE AHn A@i t Ung cNa l p cd sL o ( virtual base class) '% (a" 46: Không chuyCn m$t const thành m$t non-const M$t sg ép kiCu t :ng minh homc không t :ng mình, ph^ thu$c vào vi*c nó A Uc ordered b:i l+p trình viên homc trình biên d ch. Ép kiCu t :ng minh ( casts) A Uc s. d^ng khi l+p trình viên mu@n get around h* th@ng kiCu cNa trình biên d ch. Ép kiCu t :ng minh gi,a nh,ng A@i t Ung khác kiCu se làm cho code khó AC AZc. Ép kiCu t :ng minh ( casts) nên A Uc s. d^ng trong tr :ng hUp con trE l p cd sd trE AHn l p d n xu t A Uc dùng. Vi*c này x y ra khi, ví d^, m$t heterogeneous container class A Uc s. d^ng AC hi*n thgc m$t container class AC chTa con trE AHn A@i t Ung d n xu t. L p m i này có thC A Uc làm “type-safe” nHu programmer exclude object khác hdn là con trE l p d n xu t from being stored. C sg thgc thi này hoJt A$ng, Ai-u c n thiHt là con trE l p cd sL A Uc chuyCn sang con trE l p d n xu t khi chúng A Uc removed khEi heterogeneous container class. Hai lý do trên cho vi*c s. d^ng explicit casts hoàn toàn không xu t hi*n n,a khi template A Uc A a vào hoJt A$ng trong C++. Có hai kiCu ép kiCu không t :ng minh: homc là có m$t sg chuyCn cNa m$t hàm tP kiCu này thành kiCu khác, A Uc viêt bLi programmer, homc là trình biên d ch se thgc hi*n nó theo chu†n cNa ngôn ng,. Nh ng c hai tr :ng hUp có thC phát sinh v n A-. C++ là m$t ngôn ng, d dãi trong v n A- biHn mà A Uc s. d^ng nh là A@i s@ cNa m$t hàm. NHu không có hàm mà phù hUp v i kiCu cNa A@i s@ thì compiler se c@ gang A- convert kiCu AC tìm m$t kiCu phù hUp. Cái b t lUi L Aây là nHu có nhi-u hdn m$t hàm phù hUp A Uc tìm th y, m$t lki biên dich se A Uc phát sinh. T* hdn n,a là code mà compiler cho phép trong ng, c nh này se chTa lki mà khi m$t sg ép kiCu không t :ng minh A Uc dùng trong code này. M$t hi*u Tng l khác cNa vi*c ép kiCu không t :ng minh là A@i t Ung tJm A Uc tJo ra trong vi*c chuyCn kiCu. @i t Ung này se là A@i s@ cNa hàm, không ph i là A@i t Ung g@c A Uc truy-n. nh nghoa cNa ngôn ng, ngfn c m vi*c gán m$t A@i t Ung tJm cho m$t non-constant reference, nh ng ph n l n compiler v n cho phép Ai-u này. Trong ph n l n tr :ng hUp, vi*c này có nghoa là ch dng trình se không hoJt A$ng m$t cách hoàn h o. Nên c†n th+n v i constructor mà s. d^ng chi m$t A@i s@, bLi vì vi*c này se d n AHn m$t sg ép kiCu m i mà trình biên d ch có thC s. d^ng m$t cách không mong mu@n khi nó th y hUp lý trong m$t tình hu@ng xác A nh. NgoJi l* A@i v i Rule 43 L p cd sL o chng gây ra v n A- ép kiCu. Có thC chuyCn m$t con trE, trE AHn m$t thgc thC cNa m$t class có l p cd sL o, AHn m$t con trE trE AHn m$t A@i t Ung cNa l p cd sL o. Sg chuyCn ng Uc lJi không A Uc phép, i.e. sg chuyCn kiCu không có tính A o ng Uc. Vì lí do này, chúng ta không nên chuyCn m$t con trE trE AHn l p l p d n xu t trE AHn m$t con trE cNa l p cd sL o. C có thC tr v- A@i t Ung tJm non-const, Aôi lúc vi*c ép kiCu t :ng minh A Uc s. d^ng AC chuyCn m$t const member data thành m$t non-const. ây không ph i là m$t thói quen l+p trình t@t, bLi vì có thC là trình biên d ch se c p phát nh,ng hKng s@ trên ROM. Exception to Rule 44:
Ép kiCu t :ng minh A Uc s. d^ng AC chuyCn m$t con trE trE AHn l p cd sL thành m$t con trE trE AHn l p d n xu t trogn type-safe container class mà A Uc hi*n thgc s. d^ng heterogeneous container class. Ép kiCu t :ng minh A Uc s. d^ng AC chuyCn m$t anonymous bit-stream thành m$t object. Vi*c này x y ra khi unpacking m$t message thành m$t message buff•. Tóm lJi, Ép kiCu t :ng minh A Uc s. d^ng AC AZc m$t external representation cNa m$t object. Exception to Rule 45: NHu m$t l p cd sL o chTa m$t hàm o, mà hàm o này chuyCn con trE trE AHn l p cd sL thành con trE trE AHn l p d n xu t, vi*c này có thC thgc hi*n bKng cách A nh nghoa hàm trong l p d n xu t. Chú ý rKng vi*c này có nghia là t t c l p d n xu t ph i A Uc hiCu trong l p cd sL o.
Ví d^ 42: Constructors with a single argument that may imply dangerous type conversions class String { public: String( int length ); // ... };
// Allocation constructor
// Function that receives an object of type String as an argument void foo( const String& aString ); // Here we call this function with an int as argument int x = 100; foo( x ); // Implicit conversion: foo( String( x ) );
Ví d^ 43:M$t cách s. d^ng ép kiCu †n: // String.hh class String { public: String( char* cp ); // Constructor operator const char* () const; // Conversion operator to const char* // ... }; void foo( const String& aString ); void bar( const char* someChars ); // main.cc
main() { foo( "hello" ); // Implicit type conversion char* -> String String peter = "pan"; bar( peter ); // Implicit type conversion String -> const char* }
Ví d^ 44:Khi ép kiCu †n cho kHt qu không mong mu@n : // This function looks bulletproof, but it isn't. // Newer versions of compilers should flag this as an error. void mySwap( int& x, int& y ) { int temp = x; x = y; y = temp; } int i = 10; unsigned int ui = 20; mySwap( i, ui ); // i u gì x y ra ây: // int T = int( ui ); // Implicit conversion // mySwap( i, T ); // ui is of course not changed! // Fortunately, the compiler warns for this !
Ví d^ 45:Ép kiCu tP con trE cNa l p g@c AHn con trE cNa l p o là không thC thay AVi A Uc class VirtualBase { public: virtual class Derived* asDerived() = 0; }; class Derived : virtual public VirtualBase { public: virtual Derived* asDerived(); }; Derived* Derived::asDerived() { return this; } void main() { Derived d;
Derived* dp = 0; VirtualBase* vp = (VirtualBase*)&d; dp = (Derived*)vp; // ERROR! Cast from virtual base class pointer dp = vp->asDerived(); // OK! Cast in function asDerived }
Ví d^ 46:Addition which leads to a compile-time error // String.hh class String { public: String( char* cp ); // Constructor operator const char* () const; // Conversion operator to const char* // ... }; void foo( const String& aString ); void bar( const char* someChars ); // Word.hh class Word { public: Word( char* cp ); // Constructor // ... }; // Function foo overloaded void foo( const Word& aWord ); // ERROR: foo( "hello" ) MATCHES BOTH: // void foo( const String& ); // AND void foo( const Word& ); //main.cc main() { foo( "hello" ); // Error ambiguous type conversion ! String peter = "pan"; bar( peter ); // Implicit type conversion String -> const char* }
Ví d^ 47:Cho vi*c thi hành hi*u qu hdn, gX bE nh,ng const-ness khi s. d^ng kHt qu trung gian: // oJn mã này không A Uc A- c. #include <math.h> class Vector { public: Vector(int, const int []); // Constructor double length() const; // length = sqrt(array[1]*array[1] + ... ) void set(int x, int value); // ... private: int size; int* array; double lengthCache; // to cache calculated length int hasChanged; // is it necessary to re-calculate length ? }; double Vector::length() const { if (hasChanged) // Do we need to re-calculate length { ((Vector*)this)->hasChanged=0; // No! Cast away const double quadLength = 0; for ( int i = 0; i < size; i++ ) { quadLength += pow(array[i],2); } ((Vector*)this)->lengthCache = sqrt(quadLength); // No! Cast away const } return lengthCache; } void Vector::set( int nr, int value ) { if ( nr >= size ) error( "Out Of Bounds"); array[nr]=value; hasChanged = 1; }
Ví d^ 48: Liên t^c loJi bE const-ness cho vi*c thgc thi có hi*u qu
// oJn mã này là an toàn hdn ví d^ 47 nh ng có thC kém hi*u qu #include <math.h> class Vector { public: Vector(int, const int []); // Constructor double length() const; // length = sqrt(array[1]*array[1] + ... ) void set(int x, int value); // ... private: int size; int* array; double* lengthCache; // to cache length in int* hasChanged; // is it necessary to re-calculate length ? }; Vector::Vector(int sizeA, const int arrayA[]) : size(sizeA), array( new int[sizeA] ), hasChanged(new int(1)), lengthCache(new double) { for ( int i = 0; i < size; i++ ) { array[i] = arrayA[i]; } } Vector::~Vector() // Destructor { delete array; delete hasChanged; delete lengthCache; } // Continue on next page ! double Vector::length() const { if (hasChanged) // Do we need to re-calculate length ? { *hasChanged=0; double quadLength = 0; for ( int i = 0; i < size; i++ ) { quadLength += pow(array[i],2);
} *lengthCache = sqrt(quadLength); } return lengthCache; } void Vector::set( int nr, int value ) { if ( nr >= size ) error( "Out Of Bounds"); array[nr]=value; *hasChanged = 1; }
14. Kh@i c u trúc Ai-u khiCn (Flow Control Structures) '% (a" 47: Code sau label case ph i luôn luôn A Uc kHt thúc bLi break. '% (a" 48: M$t phát biCu switch ph i luôn luôn chTa m$t default branch (AC A- phòng tr :ng hUp ngoJi l* phát sinh). '% (a" 49: Không bao gi: s. d^ng goto. '% (a" 50: Vi*c lga chZn c u trúc lmp ( for, while, do-while) ph^ thu$c vào Amc AiCm cNa vòng lmp. - ". 37: Luôn luôn s. d^ng unsigned cho biHn mà không có giá tr âm - ". 38: Nên s. d^ng inclusive lower limit và exclusive upper limits. - ". 39: Tránh s. d^ng continue - ". 40: S. d^ng break AC thoát khEi vòng lmp nHu vi“c này tránh s. d^ng c:. - ". 41: Không viHt biCu thTc lô-gíc theo kiCu if (test) or if (!test) khi test là m$t pointer.
Mki c u trúc lmp có m$t sg h,u d^ng riêng. C u trúc for A Uc s. d^ng khi biHn lmp ( loop variable) tfng m$t l Ung không AVi cho mki l n lmp và khi Ai-u ki*n kHt thúc cNa vòng lmp A Uc xác A nh bLi m$t biCu thTc hKng. Trong tr :ng hUp khác, while or do-while nên A Uc s. d^ng. Khi Ai-u ki*n kHt thúc A Uc tính toán tJi A u cNa vòng lfp, while nên A Uc s. d^ng; do-while A Uc s. d^ng khi Ai-u ki*n kHt thúc A Uc tính toán tJi cu@i vòng lmp. Goto thoát khEi lu1ng Ai-u khiCn ( flow control) và có thC d n AHn vi*c khó hiCu code. Ngoài ra, có sg gi i hJn khi goto A Uc s. d^ng. Ví d^, không A Uc phép nh y trL lJi m$t câu l*nh mà khLi tJo m$t object c^c b$ có destructor. Nh,ng biHn mà th :ng A Uc dùng AC miCu t kích th c và chi-u dài th :ng AuUc khai báo là unsigned. BKng cách s. d^ng cách này có thC tránh A Uc m$t vài lki khó ch u phát sinh mà ta không kiCm soát A Uc. T@t nh t là nên s. d^ng inclusive lower và exclusive upper limits. Thay vì nói rKng biHn x trong kho ng x>=23 và x<=42, s. d^ng gi i hàn x>=23 và x<43. Vi*c này có nh,ng lUi ích sau: + Kích th c cNa kho ng biHn thiên cNa x là hi*u cNa hai gi i hJn ( 43-23). + Gi i hJn bKng nhau nHu kho ng biHn thiên là rkng. + Gi i hJn trên không bao gi: nhE hdn gi i hJn d i. BKng cách trên thì nhi-u lki có thC tránh A Uc. NHu code sau lable case không kHt thúc bLi break, vi*c thgc thi tiHp túc sau lable case kH tiHp. Vi*c này se gây ra lki cho ch dng trình. Continue có thê A Uc s. d^ng AC thoátt khEi vòng lmp. Tuy nhiên, code có thC se d hiCu hdn bKng cách s. d^ng else bLi . Chú ý AHn t m vgc mà biHn chJy ( iteratioin variable) visible. M$t biHn A Uc khai báo trong vong for thì chi visible trong kh@i A Uc bao bLi cmp d u “{}” cNa vòng for Aó. Exception to Rule 47: Khi m$t vài label case có s. d^ng chung m$t block code, chi m$t phát biCu break là c n thiHt.
Ví d^ 49:V n A- s. d^ng kiCu unsigned trong biHn cNa vòng lmp: for( unsigned int i = 3; i >= 0; --i ) { // Vòng lmp se không bao gi: dPng, tP khi i Ai qua chu trình: // 3, 2, 1, 0, 4294967295, 4294967294, etc ... on a SparcStation // Note that this example does not follow the rules: i >= 0 // in the for statement. See next example ! }
Ví d^ 50:Khai báo Aã A Uc nhìn th y trong vòng for: for ( int index = 0; index < 10; index++ ) { cout << index; } int index = 3; // L I, ÂY LÀ M T S KHAI BÁO L I KHÔNG H P LÍ C A index // B I VÌ index C KHAI BÁO TRONG VÒNG FOR.
Ví d^ 51:Câu l*nh switch/case và sg nguy hiCm switch ( tag ) { case A:
{ // Không làm cái gì // L nh k ti p cg i
n foo()trong case k ti p
} case B: { foo(); // Không làm cái gì break; // Bây gi thi chúng ta thoát l nh switch } default: { // If no match in above cases, this is executed exit( 1 ); } }
Ví d^ 52:Nh,ng cách t@t và x u sg b@ trí có gi i hJn cho nh,ng biHn trong vòng lmp int a[10]; int ten = 10; int nine = 9; // Cách t t làm i u này: for( int i = 0; i < ten; i++ ) { a[i] = 0; } // X u khi làm nh sau: for( int j = 0; j <= nine; j++ ) { a[j] = 0; }
// Loop runs 10-0=10 times
// Loop runs 10 times, but 9-0=9 !!!
Ví d^ 53:S. d^ng break AC thoát vòng lmp ,không flags c n thiHt do {
// Cách này:
if ( Something ) { // Do something break; } } while( someCondition ); int endFlag = 0;
// là t t h n cách sau:
do { if ( /* Something */ ) { // Do something endFlag = 1; } } while( someCondition && !endFlag );
Ví d^ 53:BKng cách thêm vào else, continue c n tránh AC code d hiCu hdn: while( /* Something */ ) { if( /* Something */ ) { // Do something } else { // Do something else } }
//Cách này rõ ràng
while( /* Something */ ) // h n s d ng continue { if( /* Something */ ) { // Do something continue; // Không c! } // Do something else }
15. BiCu thTc(Expression) - ". 42: S. d^ng d u ngomc Adn AC làm rõ ràng thT tg tính toán cNa toán t. trong biCu thTc.
C@ m$t vài lki hay gmp trong vi*c tính toán m$t biCu thTc. Toán t. hai ngôi ( binary operator) trong C++ có tính kHt hUp ( trái homc ph i) và A$ u tiên. NHu m$t toán t. có tính kHt hUp trái và xu t hi*n L hai bên cNa m$t biHn trong m$t biCu thTc, thì biHn thu$c v- cùng m$t phàn cNa biCu thTc nh là toán t. bên phía trái cNa nó. M$t nh m l n phV biHn hay gmp là toán t. gán(assignment) và toán t. bKng( equality). Ví d^, toán t. << ( shift left) và >> ( shift right) th :ng A Uc s. d^ng trong input và output. BLi vì Aây là nh,ng toán t. bit, chúng có A$ u tiên cao hdn so v i toán t. quan h* ( relational operator). i-u này có ngho là d u ngomc Adn ph i A Uc s. d^ng khi xu t giá tr cNa biCu thTc logic.
Ví d^ 54:V n A- khi
c l Uc các d u ngomc
// Interpreted as ( a
Ví d^ 55:D u ngomc Adn A Uc A- c. int i = a >= b && c < d && e + f <= g + h; int j = ( a >= b ) && ( c < d ) && (( e + f ) <= ( g + h ));
// Không nên! // T t h n
16. C p phát b$ nh : '% (a" 51: Không s. d^ng malloc, realloc or free. '% (a" 52: Luôn luôn dùng empty brackets (“[]”) cho delete khi deallocate m$t array. - ". 43: Tránh s. d^ng d, li*u toàn c^c nHu có thC. - ". 44: Png có c p phát b$ nh và hy vZng rKng se có ai Aó deallocate nó sau này. - ". 45: Luôn luôn gán m$t giá tr m i cho m$t con trE mà trE AHn vùng nh Aã b deallocate.
Trong C++ d, li*u có thC A Uc c p phát, A$ng trên stack, homc A$ng trên heap. Có ba kiCu d, li*u tính: d, li*u toàn c^c, d, li*u l p toàn c^c ( global class data) và d, li*u tonh c^c b$ A@i v i m$t hàm ( static data local to a function). Se là nguy hiCm nHu : 1. gZi hàm delete m$t con trE obtained vai maaloc/realloc, 2. gZi hàm malloc/realloc cho nh,ng l p có constructor. 3. gZi hàm free cho b t cT cái gì mà A Uc c p phát bLi “new” Vì v+y, tránh nHu có thC vi*c s. d^ng malloc, realloc, và frê. NHu m$t array a có kiCu T A Uc c p phát, vi*c quan trZng là gZi delete theo Aúng cách. Chi viHt delete a, se d n AHn destructor d Uc thgc hi*n chi for first object cNa kiCu T. BKng cách viHt delete [m] a, m là m$t s@ nguyên l n hdn s@ l :ng A@i t Ung A Uc c p phát tr c Aây, destructor cNa T se A Uc gZi cho vùng b$ nh àm không represent l p kiCu T. Cách Adn gi n nh t AC làm vi*c này là viHt delete d a; bLi vì destructor se A Uc thgc thi chi cho nh,ng object Aã A Uc c p phát tr c Aây.
Ví d^ 56: Cách Aúng và sai AC xóa m$t m ng v i destructors int n = 7; T* myT = new T[n]; // T is a type with defined constructors and destructors // ... delete myT; // Không thC! Destructor chi A Uc gZi cho A@i t Ung A u tiên trong m ng delete [10] myT; // Không thC! Destructor called on memory out of bounds in array a delete [] myT;
// T t, và luôn luôn an toàn!
Ví d^ 57:Nh,ng nguy hiCm khi c p phát b$ nh : String myFunc( const char* myArgument ) { String* temp = new String( myArgument ); return *temp; //temp là không bao gi deallocated và ng i s d ng hàm myFunc không th deallocate // b!i vì m t b n t m c a instance không c tr l i. }
17. Mã linh A$ng(Portable Code)
17.1 Data Abstraction ( TrPu t Ung hoá d, li*u) - c. kh chuyCn 1: Tránh s. d^ng trgc tiHp nh,ng kiCu d, li*u Aã A Uc A nh nghoa tr
c trong khai báo.
M$t cách tuy*t v:i AC chuyCn your world thành “thung lhng n c mat” ( vale of tears) là s. d^ng trgc tiHp nh,ng d, li*u A Uc A nh nghoa s’n trong khai báo. NHu sau này,trong tr :ng hUp c n thiHt, bLi vì v n A- portability, AC thay AVi kiCu tr v- cNa m$t hàm, có thC se thay AVi nhi-u ndi trong code. M$t cách AC tránh Ai-u này là khai báo m$t kiCu tr v- m i s. d^ng nh,ng l p homc typedef AC miêu t kiCu cNa biHn A Uc s. d^ng. BKng cách này, ta có thC d dàng tJo sg thay AVi hdn. Vi*c này có thC A Uc s. d^ng AC gán m$t Adn v d, li*u v+t lý, chnng hJn nh kilogram hay meter. Nh,ng AoJn code nh va”a thì d dàng xem lJi hdn ( Ví d^, khi code không chJy t@t, có thC là m$t biHn miêu t meter A Uc gán cho m$t biên miêu t kilogram). Chú ý rKng typedef không tJo ra kiCu m i, chi là m$t cái tên khác cho m$t kiCu. Có nghoa là nHu khai báo typedef int Error, m$t biHn có kiCu Error có thê A Uc s. d^ng L b t cT ndi Aâu mà biHn ini A Uc sN d^ng
Ví d^ 58:KiCu khai báo s. d^ng typedef // Thay vì long int time; short int mouseX; char* menuName; // S d ng (for example): typedef long int TimeStamp; typedef short int Coordinate; class String { /* ... */ }; // và: TimeStamp time; Coordinate mouseX; String menuName;
17.2 Kích th
c cNa kiCu:
- c. kh chuyCn 2: Không nên ngho rKng m$t biHn kiCu int và long có cùng kích th c. - c. kh chuyCn 3: Không nên ngho rKng m$t biHn int dài 32 bits ( nó có thC chi dài có 16 bits). - c. kh chuyCn 4: Không nên ngho rKng m$t char là có d u hay không d u. - c. kh chuyCn 5: Luôn luôn gán char to unsigned if 8-bit ASCII A Uc s. d^ng. Trong A nh nghoa cNa ngôn ng, C++ thì m$t char ch a biHt là có d u hay không d u. Vi*c này ph^ thu$c vào compiler. NHu s. d^ng char theo cách này hay theo cách khác ( có d u hay không có d u), thì có thC se có bugs xu t hi*n truogn ch dng trình khi compiler khác A Uc s. d^ng. NHu 8-bits ASCII A Uc s. d^ng và phép so sánh hai kí tg A Uc thgc hi*n, thì unsigned char A Uc s. d^ng.
17.3 ChuyCn kiCu
- c. kh chuyCn 6: C†n th+n nHu chuyCn kiCu tP kiCu ngan hdn thành kiCu dài hdn. - c. kh chuyCn 7: Không nên ngho rKng pointer và integer có cùng kích th c. - c. kh chuyCn 8: S. d^ng Ép kiCu t :ng minh cho nh,ng phép tính s@ hZc s. d^ng giá tr không d u và có d u. KiHn trúc cNa b$ vi x. lý th :ng c m vi*c m$t d, li*u có kích th c c@ A nh A Uc c p phát cho m$t A a chi b t kì nào Aó. Ví d^, m$t tP ph i bat A u bKng m$t A a chi “chnng” fE MC680x0. NHu có m$t con trE trE AHn m$t char mà A Uc xác A nh là có A a chi “l•”, m$t sg chuyCn AVi kiCu tP con trE trE AHn kí tg này thành con trE int se là cho ch dng trình ATng khi con trE int A Uc sN d^ng, bLi vì vi*c này vi phJm nguyên tac cNa b$ x. lý trong vi*c gán d, li*u.
17.4 Mô t d, li*u (Data Representation) - c. kh chuyCn 9: Không nên ngho rKng d, li*u kiCu long,float, double, hay long double bat A u L b t c. A a chi nào. Vi*c biCu di n kiCu d, li*u trong b$ nh thì ph^ thu$c r t nhi-u vào máy tính. BKng cách c p phát data members cho m$t vùng nh nào Aó, b$ vi x. lý thgc thi code hi*u qu hdn. BLi vì Ai-u này, c u trúc d, li*u mà biCu di n m$t l p se A Uc chTa theo nh,ng cách khác nhau trong nh,ng kiHn trúc máy tính khác nhau. Code ph^ thu$c vào m$t specific represention thì không thC nói là portable A Uc.
17.5 Underflow/Overflow - c. kh chuyCn 10: Không nên ngho rKng A@i t Ung tonh A Uc khLi tJo theo m$t tr+t tg cho tr
c.
NHu giá tr A Uc chinh s.a hai l n trong cùng m$t biCu thTc, kHt qu cNa biCu thTc thì không A Uc xác A nh ngoJi trP khi thT tg tính toán A Uc A m b o cho nh,ng toán t. s. d^ng nó. ThT tg khLi tJo nh,ng A@i t Ung tonh có thC se làm phát sinh ra m$t s@ v n A-. M$t A@i t Ung tonh không A Uc s. d^ng trong constructor, nHu nó không A Uc khLi tJo cho AHn sau khi constructor A Uc gZi thgc thi. Lúc này, thP tg khLi tJo cNa nh,ng A@i t Ung tonh, A Uc A nh nghoa trong nh,ng Adn v biên d ch khác nhau, thì không A Uc xác A nh. Vi*c này d n AHn nh,ng lki mà khó AC xác A nh . Có vài ko thu+t AC tránh tình trJng này .
Ví d^ 59: Do not depend on the order of initialization in constructors. #include class X { public: X(int y);
private: int i; int j; }; inline X::X(int y) : j(y), i(j) // No! j may not be initialized before i !! { cout << "i:" << i << " & " << "j:" << j << endl; } main() { X x(7); }
// Rather unexpected output: i:0 & j:7
Ví d^ 60:KhLi tJo m$t A@i t Ung tonh(static objects) // Foo.hh #include #include <string.h> static unsigned int const Size = 1024; class Foo { public: Foo( char* cp ); // ... private: char buffer[Size]; static unsigned counter; }; extern Foo foo_1; extern Foo foo_2; // Foo1.cc #include "Foo.hh" unsigned Foo::counter = 0; Foo foo_1 = "one"; //Foo2.cc #include "Foo.hh"
// Constructor
// Number of constructed Foo:s
Foo foo_2 = "two"; Foo::Foo( char* cp ) // Irrational constructor { strncpy( buffer, cp, sizeof(buffer) ); foos[counter] = this; switch ( counter++ ) { case 0: case 1: cout << ::foo_1.buffer << "," << ::foo_2.buffer << endl; break; default: cout << "Hello, world" << endl; } } // If a program using Foo.hh is linked with Foo1.o and Foo2.o, either // ,two or one, is written on standard output depending on // one,two one,two the order of the files given to the linker.
17.5
@i t Ung tJm :
- c. kh chuyCn 11: - Không viHt code mà ph^ thu$c vào th:i gian s@ng cNa A@i t Ung tJm. - @i t Ung tJm th :ng A Uc tJo ra trong C++, chnng hJn nh khi hàm tr v- m$t giá tr . Nhi-u lki khó xác A nh có thC phát sinh khi có m$t con trE trE AHn m$t A@i t Ung tJm.
Ví d^ 60: Difficult error in a string class which lacks output operator class String { public: operator const char*() const; // Conversion operator to const char* friend String operator+( const String& left, const String& right ); // ... }; String a = "This may go to "; String b = "h***!"; // The addition of a and b generates a new temporary String object. // After it is converted to a char* by the conversion operator, it is // no longer needed and may be deallocated. This means that characters // which are already deallocated are printed to cout -> DANGEROUS!! cout << a + b;
17.6 Pointer Arithmetic - c. kh chuyCn 12: Tránh s. d^ng toán t. shift thay cho toán t. s@ hZc
Tránh s. d^ng pointer arithmetic Pointer arithmetic thì linh A$ng. Toán t. “==” và “!=”A Uc A nh nghoa cho t t c các pointer cNa cùng kiCu d, li*u, trong khi toán t. <,>,<=,>= thì linh A$ng chi khi chúng A Uc s. d^ng gi,a nh,ng con trE mà trE AHn cùng m$t m ng.
18.Sách tham kh o 1. The Annotated C++ Reference Manual, Bjarne Stroustrup/Margareth Ellis[ARM], Addison Wesley 1990, ISBN 0-201-51459-1. This book forms the basis of the work in the ANSI-C++ committee. 2. C++ Primer, Second Edition, Stanley B. Lippman, Addison Wesley 1991, ISBN 0-201-54848-8. Very good for learning the basics of C++. 3. The C++ Programming Language, Second Edition, Bjarne Stroustrup, Addison Wesley 1991, ISBN 0-201-53992-6. This second edition has been completely updated with the current (and future) language definition. It will most certainly become a standard reference book. 4. Advanced C++ Programming Styles and Idioms, James O. Coplien, Addison Wesley 1992, ISBN 0210-54855-0. Possibly the most advanced book on how to use C++. Contains many tricks and tips. 5. Object-oriented Software Construction, Bertrand Meyer, Prentice Hall 1988, ISBN 0-13-629049-3 or 0-13-629031-0 PBK Somewhat of a classic work. Examples are written in Eiffel. 6. Data Abstraction and Object-Oriented Programming in C++, Keith E. Gorlen, Sanford M. Orlow and Perry S. Plexico, John Wiley & Sons 1990, ISBN 0 471 92346 X pbk or 0 471 92751 1. The book that describes the class library NIH. Includes many good examples. 7. Object-Oriented Design with Applications, Grady Booch, Benjamin/Cummings 1991, ISBN 0-80530091-0. Treats the design and implementation of software in various object-oriented languages.
8. Recommended C Style and Coding Standards, Bell Labs, Zoology Computer Systems University of Toronto, CS University of Washington, November 18, 1989. A collection of rules for programming in C. Contains a good section on portability. 9. A Guide to Natural Naming, Daniel Keller, ETH, Projekt-Zentrum IDA, CH-8092 Zurich, Switzerland A guide on how to choose good names for functions and variables. Not adapted to object-oriented programming. 10. Advanced C++, Jonathan E. Shopiro, Binder with material from course held in Lund (Sweden) from June 4 to June 7, 1991. Filled with warnings and tips. 11. Objektorienterad programmering och biblioteksuppbyggnad i C++, Martin Carrol. Material from course held in Stockholm (Sweden) on April 18, 1991. Presents useful viewpoints on problems which may arise when designing a class library. 12. Automatic Detection of C++ Programming Errors: Initial Thoughts on a lint++, Scott Myers/Moises Lejter, Usenix C++ Conference Proceedings, Spring 91. Article which describes some programming rules for C++. 13. Code-Style Prescriptions Carl R. Dickler, Unix Review, 9(9), 1991, pages 41-45. Article which describes a number of programming rules for C and which discusses why programming rules are needed.