Effective C++ 学习历程001
自从大一下接触C++面向对象程序设计,我就对一直在学习C++ 这门语言,当然了也一直很喜欢C++。在之前刚刚开始C语言程序设计时,自己还不喜欢编程这门学问。后来,慢慢喜欢上编程,正是跟随着C++ 语言的慢慢学习与积累的。嗯,我很喜欢C++这门语言!那就从一本挚爱的图书《Effective C++ 》开始吧,也当是给“Effective C++ 学习历程”做个简单的开始。
1
namespace
testItem01
2 {
3 } // namespace testItem01
4 // ====================================================================
5 // --- 条款02:尽量以const,enum,inline替换 #define
6 // 注意:
7 // 1 对于单纯变量,最好以const 对象或是 enumS 替换 #defineS 。。。
8 // 2 对于形似函数的 宏(mactos),最好改用inline(结合 template) 函数替换 #defineS
9 // 3
10 namespace testItem02
11 {
12 template < typename T >
13 inline T MAX_TEMP( const T & a , const T & b)
14 { return (a > b ? a : b) ; }
15 void exampleFunc()
16 {
17 cout << " define constant ,using #define ,enum , const Type \n " ;
18 #define DEFINE_NUM 10
19 enum { ENUM_NUM = 10 } ; // ..
20 const int CONST_NUM = 10 ;
21 cout << " DEFINE_NUM ENUM_NUM CONST_NUM : "
22 << DEFINE_NUM << setw( 5 ) << ENUM_NUM << setw( 5 ) << CONST_NUM << " \n " ;
23 /*
24 char str1[DEFINE_NUM] ; // okokok
25 char str2[ENUM_NUM] ;// okokok
26 char str3[CONST_NUM] ;// okokok
27 */
28 // #define 导致的错误 ..
29 cout << " Error , use #define \n " ;
30 #define MAX_DEFINE(a,b) ((a) > (b) ? (a) : (b))
31 int a = 5 , b = 0 ;
32 cout << " a = 5, b = 0; MAX_DEFINE(++a, b): " ;
33 cout << MAX_DEFINE( ++ a, b) << " \n " ; // a 的值增加了2次
34 cout << " a: " << a << " ,MAX_DEFINE(++a, b+10) : " ;
35 cout << MAX_DEFINE( ++ a, b + 10 ) << " \n " ; // a 的值只增加了1次
36 cout << " a: " << a << " \n " ;
37 cout << " OKOKOK , use inline template \n " ;
38 a = 5 , b = 0 ;
39 cout << " a = 5, b = 0; MAX_TEMP(++a, b): " ;
40 cout << MAX_TEMP( ++ a, b) << " \n " ; // a 的值增加了2次
41 cout << " a: " << a << " MAX_TEMP(++a, b+10) : " ;
42 cout << MAX_TEMP( ++ a, b + 10 ) << " \n " ; // a 的值只增加了1次
43 cout << " a: " << a << " \n " ;
44 }
45 } // namespace testItem02
46 // ====================================================================
47 // --- 条款03:尽量使用 const
48 // 注意:
49 // 1 将某些东西声明为 const可以帮助编译器侦测出错误语法。const可被施加于任何作用域内的
50 // 对象、函数参数、函数返回类型、成员函数本体
51 // 2 编译器强制执行(实施)bitwise constness 。但你编写程序时应该使用“概念上的常量性”(conceptual constness)
52 // 3 当 const 和 non-const成员函数有着实质等价的实现时,令non-const版本去调用const版本可避免代码重复 。
53 namespace testItem03
54 {
55 void func1( const char * pChar) { cout << " void func1(const int* pInt): " << pChar << " \n " ; } //
56 void func2( char const * pChar)
57 { cout << " void func2(int const * pInt): " << pChar << " \n " ;} // the same as func1
58 // -------------------------
59 class TextBlock
60 {
61 private :
62 std:: string text_ ;
63 public :
64 TextBlock() {}
65 // TextBlock(const char* str) : text_(str) {} //
66 TextBlock( const std:: string & str) : text_(str) {} //
67 //
68 const char & operator [](std::size_t pos) const
69 {
70 cout << " const char& operator [](std::size_t pos) const \n " ;
71 return text_[pos] ;
72 }
73 /* 1 ==========
74 char& operator [](std::size_t pos)
75 {
76 cout << " char& operator [](std::size_t pos) //1==\n " ;
77 return text_[pos] ;
78 } */ // 2 ========== non-const 跳转 const 版本 + 过程转换
79 char & operator [](std::size_t pos)
80 {
81 cout << " char& operator [](std::size_t pos) //2==\n " ;
82 return const_cast < char &> (static_cast < const TextBlock > ( * this )[pos] ) ;
83 }
84 //
85 } ;
86 void print_0( const TextBlock & ctb)
87 { cout << " ctb[0]: " << ctb[ 0 ] << " \n " ; } // 调用const char& operator [](std::size_t pos) const
88 // ------------关键字 mutable mutable mutable ---------
89 class CTextBlock
90 {
91 private :
92 char * pText ;
93 mutable size_t textLength ; // 可以在 const成员函数改变该成员变量
94 mutable bool lengthIsValid ; // 可以在 const成员函数改变该成员变量
95 public :
96 size_t length() const ;
97 //
98 } ;
99 size_t CTextBlock::length() const // 可以在 const成员函数改变该成员变量 textLength ,lengthIsValid
100 {
101 if ( ! lengthIsValid)
102 {
103 textLength = std::strlen(pText) ;
104 lengthIsValid = true ;
105 }
106 return textLength ;
107 }
108 //
109 void exampleFunc()
110 {
111 char greeting[] = " Hello " ;
112 char * p = greeting ; // non-const pointer ,non-const data
113 const char * cp = greeting ; // non-const pointer ,const data
114 char * const pc = greeting ; // const pointer ,non-data
115 const char * const cpc = greeting ; // const pointer ,const data
116 func1(p) ; func1(cp) ; func1(pc) ; func1(cpc) ;
117 func2(p) ; func2(cp) ; func2(pc) ; func2(cpc) ;
118 // -------------------------------------------
119 std::vector < int > iVec( 5 , 1 ) ;
120 //
121 cout << " *iVec.begin(): " << * iVec.begin() << " \n " ;
122 const vector < int > ::iterator it = iVec.begin() ; // const vector<T>::iterator == T* const
123 * it = 10 ; // 没有问题,实际改变it所指物,但违背正常逻辑
124 // ++it ; // 错误!it 是 const == T* const 、、Error
125 // error: passing `const __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >'
126 // as `this' argument of `__gnu_cxx::__normal_iterator<_Iterator, _Container>& __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator++()
127 // [with _Iterator = int*, _Container = std::vector<int, std::allocator<int> >]' discards qualifiers|
128 cout << " *iVec.begin(): " << * iVec.begin() << " \n " ;
129 vector < int > ::const_iterator cit = iVec.begin() ; // vector<T>::const_iterator == const T*
130 // *cit = 1 ; // 错误! *cit(所指物)是const
131 // error: assignment of read-only location|
132 ++ cit ; // 没有问题,改变 cit ,指向下一个所指物
133 // -------------------------------------------
134 TextBlock tb( " Hello " ) ;
135 cout << " " << tb[ 0 ] << " \n " ;
136 const TextBlock ctb( " Hello " ) ;
137 cout << " " << ctb[ 0 ] << " \n " ;
138 cout << " print_0(tb) ; \n " ;
139 print_0(tb) ;
140 }
141 } // namespace testItem03
142 // ====================================================================
143 // --- 条款04:确定对象被使用前先被初始化
144 // 注意:
145 // 1 为内置型对象进行手工的初始化,因为C++ 不保证初始化它们
146 // 2 构造函数最好使用成员初值列表初始化成员变量( member initializatiob list) ,
147 // 而不要在构造函数本体内使用赋值操作(assignment)。初始列表列出的成员变量,其排列次序应该跟
148 // 它们在class 中的声明次序相同。(而class 中的声明次序应该符合逻辑)
149 // 3 为免除“跨编译单元之初始化次序”问题,请以local static 对象替换 non-local static 对象。
150 // 4 对于大多数类型而已,比起先调用default构造函数日后再调用copy assignment操作符,单只调用
151 // 一次构造函数是比较高效的,有时甚至高效得多。(而对于内置类型基本一样,差不多)
152 // 在“初始化次序不确定性”(这对不同编译但愿所定义的non-local static对象是一种折磨)氛围下
153 // 加强你的设计,你可以考虑 以上 3 点的策略 non-local static -->> local static转化 !!!
154 namespace testItem04
155 {
156 class PhoneNumber {} ; // .
157 class ABEntry
158 {
159 private :
160 string name_ ;
161 string address_ ;
162 std::list < PhoneNumber > phones_ ;
163 int numTimesConculted ;
164 public :
165 ABEntry() ;
166 ABEntry( const string & name , const string & addr ,\
167 const list < PhoneNumber > phones )
168 : name_(name) ,address_(addr) ,phones_(phones) ,\
169 numTimesConculted( 0 ) // 初始化列表初始化 data member
170 {} // 主体为空 记住根据class定义data member次序初始化 .
171 /*
172 {
173 name_ = name ; //这些都是赋值--assignments
174 address_ = addr ;//而不是 初始化--initilizations
175 phones_ = phones ;
176 numTimesConculted = 0 ;
177 } */
178 } ;
179 ABEntry::ABEntry():name_() ,address_() ,phones_() ,numTimesConculted( 0 )
180 {} // 记住根据class定义data member次序初始化 .
181 // ----------------------------------
182 // -------- one.h ---------- // // 多编译单元情况
183 class FileSystem
184 {
185 public :
186 FileSystem() :numDisks_( 0 ) {} // ..
187 FileSystem( int numDisks) :numDisks_(numDisks) {} // ..
188 //
189 std::size_t numDisks() const ; // 众多成员函数之一
190 //
191 private :
192 int numDisks_ ; //
193 } ;
194 std::size_t FileSystem::numDisks() const
195 { return numDisks_ ; } // // 多编译单元情况
196 // FileSystem tfs ; // okokok
197 // -------- theOther.h ---------- // // 多编译单元情况
198 FileSystem tfs_non_local_static ; // 预备给客户使用对象--
199 // extern FileSystem tfs_non_local_static ; // 预备给客户使用对象--the file system // 多文件(编译单元)
200 // .
201 FileSystem & tfs_local_static() ; // 声明函数
202 class Directory
203 {
204 private :
205 string dir_ ;
206 public :
207 explicit Directory( string dir) ;
208 //
209 } ;
210 size_t handleNumDisks(size_t num) { /* . */ return num ; } //
211 Directory::Directory( string dir) : dir_(dir)
212 {
213 //
214 // size_t disks = tfs_non_local_static.numDisks() ; // bad non-local static object
215 size_t disks = tfs_local_static().numDisks() ; // good local static object
216 handleNumDisks(disks) ;
217 //
218 }
219 // ---------------------------------------------------
220 // 3 为免除“跨编译单元之初始化次序”问题,请以local static 对象替换 non-local static 对象。
221 FileSystem & tfs_local_static()
222 // 这个函数用来替换tfs对象:它在FileSystem class 中可能是一个static
223 { // 定义并初始化一个local static对象,返回一个reference指向上述对象
224 static FileSystem fs ;
225 return fs ;
226 }
227 } // namespace testItem04
228 // === 二、构造/析构/赋值运算 ============================================
229 // ====================================================================
230 // --- 条款05:了解C++ 默默编写并调用的哪些函数:
231 // (默认)构造函数,析构函数,赋值函数,复制构造函数
232 // 注意:
233 // 1 编译期可以暗自为class 创建 default 构造函数,copy构造函数,copy assignment
234 // 操作符,以及析构函数
235 namespace testItem05
236 { // ..
237 }
238 // ====================================================================
2 {
3 } // namespace testItem01
4 // ====================================================================
5 // --- 条款02:尽量以const,enum,inline替换 #define
6 // 注意:
7 // 1 对于单纯变量,最好以const 对象或是 enumS 替换 #defineS 。。。
8 // 2 对于形似函数的 宏(mactos),最好改用inline(结合 template) 函数替换 #defineS
9 // 3
10 namespace testItem02
11 {
12 template < typename T >
13 inline T MAX_TEMP( const T & a , const T & b)
14 { return (a > b ? a : b) ; }
15 void exampleFunc()
16 {
17 cout << " define constant ,using #define ,enum , const Type \n " ;
18 #define DEFINE_NUM 10
19 enum { ENUM_NUM = 10 } ; // ..
20 const int CONST_NUM = 10 ;
21 cout << " DEFINE_NUM ENUM_NUM CONST_NUM : "
22 << DEFINE_NUM << setw( 5 ) << ENUM_NUM << setw( 5 ) << CONST_NUM << " \n " ;
23 /*
24 char str1[DEFINE_NUM] ; // okokok
25 char str2[ENUM_NUM] ;// okokok
26 char str3[CONST_NUM] ;// okokok
27 */
28 // #define 导致的错误 ..
29 cout << " Error , use #define \n " ;
30 #define MAX_DEFINE(a,b) ((a) > (b) ? (a) : (b))
31 int a = 5 , b = 0 ;
32 cout << " a = 5, b = 0; MAX_DEFINE(++a, b): " ;
33 cout << MAX_DEFINE( ++ a, b) << " \n " ; // a 的值增加了2次
34 cout << " a: " << a << " ,MAX_DEFINE(++a, b+10) : " ;
35 cout << MAX_DEFINE( ++ a, b + 10 ) << " \n " ; // a 的值只增加了1次
36 cout << " a: " << a << " \n " ;
37 cout << " OKOKOK , use inline template \n " ;
38 a = 5 , b = 0 ;
39 cout << " a = 5, b = 0; MAX_TEMP(++a, b): " ;
40 cout << MAX_TEMP( ++ a, b) << " \n " ; // a 的值增加了2次
41 cout << " a: " << a << " MAX_TEMP(++a, b+10) : " ;
42 cout << MAX_TEMP( ++ a, b + 10 ) << " \n " ; // a 的值只增加了1次
43 cout << " a: " << a << " \n " ;
44 }
45 } // namespace testItem02
46 // ====================================================================
47 // --- 条款03:尽量使用 const
48 // 注意:
49 // 1 将某些东西声明为 const可以帮助编译器侦测出错误语法。const可被施加于任何作用域内的
50 // 对象、函数参数、函数返回类型、成员函数本体
51 // 2 编译器强制执行(实施)bitwise constness 。但你编写程序时应该使用“概念上的常量性”(conceptual constness)
52 // 3 当 const 和 non-const成员函数有着实质等价的实现时,令non-const版本去调用const版本可避免代码重复 。
53 namespace testItem03
54 {
55 void func1( const char * pChar) { cout << " void func1(const int* pInt): " << pChar << " \n " ; } //
56 void func2( char const * pChar)
57 { cout << " void func2(int const * pInt): " << pChar << " \n " ;} // the same as func1
58 // -------------------------
59 class TextBlock
60 {
61 private :
62 std:: string text_ ;
63 public :
64 TextBlock() {}
65 // TextBlock(const char* str) : text_(str) {} //
66 TextBlock( const std:: string & str) : text_(str) {} //
67 //
68 const char & operator [](std::size_t pos) const
69 {
70 cout << " const char& operator [](std::size_t pos) const \n " ;
71 return text_[pos] ;
72 }
73 /* 1 ==========
74 char& operator [](std::size_t pos)
75 {
76 cout << " char& operator [](std::size_t pos) //1==\n " ;
77 return text_[pos] ;
78 } */ // 2 ========== non-const 跳转 const 版本 + 过程转换
79 char & operator [](std::size_t pos)
80 {
81 cout << " char& operator [](std::size_t pos) //2==\n " ;
82 return const_cast < char &> (static_cast < const TextBlock > ( * this )[pos] ) ;
83 }
84 //
85 } ;
86 void print_0( const TextBlock & ctb)
87 { cout << " ctb[0]: " << ctb[ 0 ] << " \n " ; } // 调用const char& operator [](std::size_t pos) const
88 // ------------关键字 mutable mutable mutable ---------
89 class CTextBlock
90 {
91 private :
92 char * pText ;
93 mutable size_t textLength ; // 可以在 const成员函数改变该成员变量
94 mutable bool lengthIsValid ; // 可以在 const成员函数改变该成员变量
95 public :
96 size_t length() const ;
97 //
98 } ;
99 size_t CTextBlock::length() const // 可以在 const成员函数改变该成员变量 textLength ,lengthIsValid
100 {
101 if ( ! lengthIsValid)
102 {
103 textLength = std::strlen(pText) ;
104 lengthIsValid = true ;
105 }
106 return textLength ;
107 }
108 //
109 void exampleFunc()
110 {
111 char greeting[] = " Hello " ;
112 char * p = greeting ; // non-const pointer ,non-const data
113 const char * cp = greeting ; // non-const pointer ,const data
114 char * const pc = greeting ; // const pointer ,non-data
115 const char * const cpc = greeting ; // const pointer ,const data
116 func1(p) ; func1(cp) ; func1(pc) ; func1(cpc) ;
117 func2(p) ; func2(cp) ; func2(pc) ; func2(cpc) ;
118 // -------------------------------------------
119 std::vector < int > iVec( 5 , 1 ) ;
120 //
121 cout << " *iVec.begin(): " << * iVec.begin() << " \n " ;
122 const vector < int > ::iterator it = iVec.begin() ; // const vector<T>::iterator == T* const
123 * it = 10 ; // 没有问题,实际改变it所指物,但违背正常逻辑
124 // ++it ; // 错误!it 是 const == T* const 、、Error
125 // error: passing `const __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >'
126 // as `this' argument of `__gnu_cxx::__normal_iterator<_Iterator, _Container>& __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator++()
127 // [with _Iterator = int*, _Container = std::vector<int, std::allocator<int> >]' discards qualifiers|
128 cout << " *iVec.begin(): " << * iVec.begin() << " \n " ;
129 vector < int > ::const_iterator cit = iVec.begin() ; // vector<T>::const_iterator == const T*
130 // *cit = 1 ; // 错误! *cit(所指物)是const
131 // error: assignment of read-only location|
132 ++ cit ; // 没有问题,改变 cit ,指向下一个所指物
133 // -------------------------------------------
134 TextBlock tb( " Hello " ) ;
135 cout << " " << tb[ 0 ] << " \n " ;
136 const TextBlock ctb( " Hello " ) ;
137 cout << " " << ctb[ 0 ] << " \n " ;
138 cout << " print_0(tb) ; \n " ;
139 print_0(tb) ;
140 }
141 } // namespace testItem03
142 // ====================================================================
143 // --- 条款04:确定对象被使用前先被初始化
144 // 注意:
145 // 1 为内置型对象进行手工的初始化,因为C++ 不保证初始化它们
146 // 2 构造函数最好使用成员初值列表初始化成员变量( member initializatiob list) ,
147 // 而不要在构造函数本体内使用赋值操作(assignment)。初始列表列出的成员变量,其排列次序应该跟
148 // 它们在class 中的声明次序相同。(而class 中的声明次序应该符合逻辑)
149 // 3 为免除“跨编译单元之初始化次序”问题,请以local static 对象替换 non-local static 对象。
150 // 4 对于大多数类型而已,比起先调用default构造函数日后再调用copy assignment操作符,单只调用
151 // 一次构造函数是比较高效的,有时甚至高效得多。(而对于内置类型基本一样,差不多)
152 // 在“初始化次序不确定性”(这对不同编译但愿所定义的non-local static对象是一种折磨)氛围下
153 // 加强你的设计,你可以考虑 以上 3 点的策略 non-local static -->> local static转化 !!!
154 namespace testItem04
155 {
156 class PhoneNumber {} ; // .
157 class ABEntry
158 {
159 private :
160 string name_ ;
161 string address_ ;
162 std::list < PhoneNumber > phones_ ;
163 int numTimesConculted ;
164 public :
165 ABEntry() ;
166 ABEntry( const string & name , const string & addr ,\
167 const list < PhoneNumber > phones )
168 : name_(name) ,address_(addr) ,phones_(phones) ,\
169 numTimesConculted( 0 ) // 初始化列表初始化 data member
170 {} // 主体为空 记住根据class定义data member次序初始化 .
171 /*
172 {
173 name_ = name ; //这些都是赋值--assignments
174 address_ = addr ;//而不是 初始化--initilizations
175 phones_ = phones ;
176 numTimesConculted = 0 ;
177 } */
178 } ;
179 ABEntry::ABEntry():name_() ,address_() ,phones_() ,numTimesConculted( 0 )
180 {} // 记住根据class定义data member次序初始化 .
181 // ----------------------------------
182 // -------- one.h ---------- // // 多编译单元情况
183 class FileSystem
184 {
185 public :
186 FileSystem() :numDisks_( 0 ) {} // ..
187 FileSystem( int numDisks) :numDisks_(numDisks) {} // ..
188 //
189 std::size_t numDisks() const ; // 众多成员函数之一
190 //
191 private :
192 int numDisks_ ; //
193 } ;
194 std::size_t FileSystem::numDisks() const
195 { return numDisks_ ; } // // 多编译单元情况
196 // FileSystem tfs ; // okokok
197 // -------- theOther.h ---------- // // 多编译单元情况
198 FileSystem tfs_non_local_static ; // 预备给客户使用对象--
199 // extern FileSystem tfs_non_local_static ; // 预备给客户使用对象--the file system // 多文件(编译单元)
200 // .
201 FileSystem & tfs_local_static() ; // 声明函数
202 class Directory
203 {
204 private :
205 string dir_ ;
206 public :
207 explicit Directory( string dir) ;
208 //
209 } ;
210 size_t handleNumDisks(size_t num) { /* . */ return num ; } //
211 Directory::Directory( string dir) : dir_(dir)
212 {
213 //
214 // size_t disks = tfs_non_local_static.numDisks() ; // bad non-local static object
215 size_t disks = tfs_local_static().numDisks() ; // good local static object
216 handleNumDisks(disks) ;
217 //
218 }
219 // ---------------------------------------------------
220 // 3 为免除“跨编译单元之初始化次序”问题,请以local static 对象替换 non-local static 对象。
221 FileSystem & tfs_local_static()
222 // 这个函数用来替换tfs对象:它在FileSystem class 中可能是一个static
223 { // 定义并初始化一个local static对象,返回一个reference指向上述对象
224 static FileSystem fs ;
225 return fs ;
226 }
227 } // namespace testItem04
228 // === 二、构造/析构/赋值运算 ============================================
229 // ====================================================================
230 // --- 条款05:了解C++ 默默编写并调用的哪些函数:
231 // (默认)构造函数,析构函数,赋值函数,复制构造函数
232 // 注意:
233 // 1 编译期可以暗自为class 创建 default 构造函数,copy构造函数,copy assignment
234 // 操作符,以及析构函数
235 namespace testItem05
236 { // ..
237 }
238 // ====================================================================