自從大一下接觸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 // ====================================================================