今天我學習的是C++操作符重載。C++的操作符重載給C++帶來很大的方便和靈活性。可以重載里面大部分操作符。這樣在調用的時候就會相對的自然和簡單。廢話少說,直接奉上源代碼(有部分相關的資料的注釋都已經寫在源代碼上了):
1 //一位是學習代碼,所以寫的相對叫亂,如果是其他的就應該規范些
2 #include<stdio.h>
3 #include <stdlib.h>
4
5 //總結:重載操作符可以寫成成員函數和友員函數。成員函數是類內部的
6 //函數,而友員函數是外部的函數,例如全局函數,甚至其他類里面的函數,我的習慣是
7 //寫成成員函數,因為我覺得這樣感覺要好一點,而且在成員函數中參數還可以少一個。
8 //哈哈,不過問題就是他不能重載左二元操作符(符號在他的左邊),也就是操作符是在他的左邊,所以在
9 //重載一個整數和這個類相加的情況就只能寫友員函數了。
10 //重載操作符的參數個數一定要跟默認參數個數的一樣,除了()這樣的可以自己定義以外,
11 //例如operator+();這是錯誤的,還有operator(int a, int b,int c);這也是錯誤的
12 //我下面之所以只有一個,是因為他是成員函數。自己已經包括在里面了,而友員就必須兩個都寫。
13 //重載的返回類型沒有規定,C++也不是用返回來判斷是否重載的,
14 //他是根據函數名和參數列表來判斷的。成員函數加const也是重載的一種,但是如果其他都一樣只有
15 //返回類型不一致,就認為是錯誤的重載。例如:
16 //int operator+(int nAdd) const;和
17 //CBaseOperator operator+(const CBaseOperator& cAdd) const;就會認為是錯誤的重載
18 //而int operator+(int nAdd) const;和int operator+(int nAdd);就是正確的,他們是兩個不同的函數
19 //在調用上,在未指明為const的類調用時,使用的是非const的函數。如果沒有非const的函數,
20 //他才會調用const的函數。而如果const的類去調用非const的函數,會直接報錯。所以
21 //在寫代碼時,可以考慮是不是可能會修改成員,如果希望是不修改的,那么請用const,這樣強制性的
22 //會提高你的編碼能力的。(扯遠了,呵呵。)
23 //都說友員是一個強大的東東,可以訪問內部的private函數和變量,但是,如果把拷貝構造函數和
24 //=重載為私有的話,他是不能訪問的。。哈哈。設計語言的人真厲害。。
25
26 //百度百科找的資料:
27 //什么時候定義類成員操作符重載,什么時候定義非類成員操作符重載?
28 //答:(1)如果一個重載操作符是類成員,那么只有當跟它一起使用的左操作數是該類對象時,
29 //它才會被調用,如果該操作符的左操作數必須是其他類型,那么重載操作符必須是非類成員操作符重載。
30 //(2)C++要求,賦值(=),下標([ ]),調用(())和成員訪問箭頭(->)操作符必須被指定為類成員操作符,否則錯誤。
31
32 //http://www.examda.com/ncre2/cpp/fudao/20080312/092830274-2.html 網站的資料
33 //不能重載的操作符號:
34 //. .* :: ?: new delete sizeof typeid static_cast dynamic_cast const_cast reintERPret_cast
35 //可以重載的操作符:
36 //operator new operator delete operator new[] operator delete[]
37 // + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == !=
38 // <= >= && || ++ -- , ->* -> () []
39 //貌似這里可以重載new
40
41 //重載簡單的+-*/%等
42 class CBaseOperator
43 {
44
45 public:
46 int nData; //測試的變量
47
48 public:
49 CBaseOperator(int nData = 0):nData(nData)
50 {
51 nData++;
52 --nData;
53 }
54
55
56 CBaseOperator(const CBaseOperator& cBO)
57 {
58 nData = cBO.nData;
59 }
60 //重載=操作符,一般=操作符和拷貝構造函數是成對出現的。
61 const CBaseOperator& operator=(const CBaseOperator& cBO)
62 {
63 nData = cBO.nData;
64 return *this;
65 }
66
67 public:
68
69 //重載+操作符,簡單的二元操作符重載是最常見也是比較簡單的。基本思路都是這樣,注意如果
70 //操作符出現在左邊,則只能用友員了。這里了有幾個返回類型是CBaseOperator,return
71 //語句中卻是兩個int相加,這種情況是可以通過的,編譯器會自動構建一個相應的對象返回,
72 //前提是你的構造函數要有相應的參數,這里是int作為參數
73 int operator+(int nAdd) const
74 {
75 return nData + nAdd;
76 }
77
78 int operator+(int nAdd)
79 {
80 return nData + nAdd;
81 }
82
83 friend int operator+(int nAdd,const CBaseOperator& cAdd)
84 {
85 return nAdd + cAdd.nData;
86 }
87
88 CBaseOperator operator+(const CBaseOperator& cAdd) const
89 {
90 return nData + cAdd.nData;
91 }
92
93 //重載減法什么的也是一樣。就不寫了。哈哈
94
95 //比較操作符重載==,!=,>, >=, <, <=總結:這里都是配套的操作一般來說如果寫一個
96 //都會重載其他幾個,特別是==,!=。當然也有例外。哈哈。。
97 bool operator==(const CBaseOperator& cEqual) const
98 {
99 return nData == cEqual.nData;
100 }
101 bool operator == (int nEqual) const
102 {
103 return nData == nEqual;
104 }
105 friend bool operator ==(int nEqual, const CBaseOperator& cEqual)
106 {
107 return cEqual.nData == nEqual;
108 }
109 bool operator!=(const CBaseOperator& cEqual) const
110 {
111 return nData != cEqual.nData;
112 }
113
114 //其他的也就不寫了,基本一樣。哈哈
115
116 //重載++,--操作符,因為++,--有兩種方式,一種是前增量(++XXX先改變自己,返回),
117 //一種是后增量(改變自己,返回改變前的狀態)
118 //因為重載是判斷參數的,為了能區別前增量和后增量,C++的設計者做了這樣的考慮。
119 //就是重載后增量的時候在參數列表中加一個int類型參數,這樣就避免的重載的重復了。
120 //在調用上,如果都重載,那么用int參數的是后增量++,沒有參數的是前增量++,
121 //(注:我在這里說的是成員函數,當然友員的重載參數個數要多一個,以后的我可別說我無知啊。)
122 //如果都重載,那么前增量和后增量都會調用相應的函數,如果只重載了后增量,那么前增量會失敗
123 //如果只重載了前增量,就會無論是前增量和后增量都會調用這個函數。所以一般他們也是成對
124 //出現的,除非你懶,只寫前增量,可惜如果人家要調用后增量呢?結果會錯的哦。哈哈。
125
126 //重載后增量.
127 CBaseOperator operator++(int)
128 {
129 CBaseOperator cTemp = *this;
130 ++nData;
131 return cTemp;
132 }
133
134 //重載前增量
135 CBaseOperator& operator++()
136 {
137 ++nData;
138 return *this;
139 }
140
141 //重載--操作符是一樣的,也不寫了。
142
143 //重載[],()等操作符號,同樣[]的參數個數是確定的。
144 //我之說以把他們寫一起,是因為我錯誤的以為[]的參數個數是可以自己定義。錯了錯了。
145 //知錯能改是好的,對了,()的參數個數是可以自己定義的。這個就給我們很大的發揮空間了。
146 //都忘了[],() = 等操作符必須是成員函數,上面有寫。不能用友員和靜態成員函數
147
148 //重載[]
149 int operator[](int nIndex) const
150 {
151 return nIndex;
152 }
153
154 //重載()
155 int operator()(int a) const
156 {
157 return a;
158 }
159
160 bool operator()(int a, int b) const
161 {
162 return a > b;
163 }
164
165 CBaseOperator operator()(int a, int b, int c)
166 {
167 return CBaseOperator(a+b+c+*this);
168 }
169
170 //重載*,->的操作符,*操作符就是相當于指針的*p;不過這里已經失去了原來的意義,他不是一個指針了。
171 //但如果是想通過他來得到一些東西,也是可以的,特別在迭代器中常用這種方法。->也是和*配對出現的。
172 //不過->操作符比較有意思,貌似和(*p).dddd真的差不多,所以返回的應該是一個結構的指針,我們這里
173 //就返回了本身,當然可以返回任何結構的指針的。(并不是只能返回本身)。
174
175 //重載*,這里參數個數是固定的,多寫一個就成了乘法的操作了。哈哈
176 int operator*() const
177 {
178 return nData;
179 }
180
181 //重載->
182 CBaseOperator* operator->()
183 {
184 return this;
185 }
186
187 //其他的例如&& || 這樣的操作符還是不重載的好。利用其原有的本性
188
189 //重載new delete,這里編譯器做了一個限制,new必須返回void*類型, delete必須
190 //返回void類型。(上面說過函數重載是不檢查返回類型的,和這里并沒有沖突,他只是限定了返回
191 //類型,而不是只有返回類型不同的函數能重載,這個是編譯器做的工作,一定上確保new能更好的工作吧)
192 //還有就是他們的參數個數都是可以自定義的。new 和 new[] 是兩個不同的操作符,所以還是要分別重載一下。
193 //delete 和 delete[] 也是兩個不同的操作符。這里只重載了一個。
194 void* operator new(size_t size)
195 {
196
197 return malloc(size);
198 }
199
200 void* operator new[](size_t size)
201 {
202 return malloc(size);
203 }
204
205 void operator delete(void* P, unsigned int size)
206 {
207 size = 0;
208 free(P);
209 }
210 };
211
212 int main()
213 {
214 const CBaseOperator cCo1(100);
215
216 //判斷+重載符
217 int nSum = cCo1 + 50;
218 printf("%d\n", nSum);
219 nSum = 50 + cCo1;
220 printf("%d\n", nSum);
221
222 //這里順便檢測一下拷貝構造函數
223 CBaseOperator co2(20);
224 CBaseOperator co3 = co2 + cCo1;
225 nSum = co3.nData;
226 printf("%d\n", nSum);
227
228 nSum = co3 + 60;
229 printf("%d\n", nSum);
230
231 //檢測+,和=操作符
232 co3 = 10 + cCo1 + co2 + 20;
233 nSum = co3.nData;
234 printf("%d\n", nSum);
235
236 //查看比較操作符
237 if (cCo1 == cCo1 && cCo1 == 100 && 100 == cCo1)
238 {
239 printf("True\n");
240 }
241 co3 = co2;
242 if (!(co3 != co2))
243 {
244 printf("True\n");
245 }
246
247 //增量操作符,cCo1是不能做這個操作的,因為他是常量
248 nSum = co2.nData;
249 printf("%d\n", nSum);
250 nSum = (co2++).nData;
251 printf("%d\n", nSum);
252 nSum = (++co2).nData;
253 printf("%d\n", nSum);
254
255 //測試[],
256 nSum = cCo1[45];
257 printf("%d\n", nSum);
258
259 //測試()
260 nSum = cCo1(50);
261 printf("%d\n", nSum);
262
263 if (cCo1(45, 23))
264 {
265 printf("True\n");
266 }
267
268 co2 = co3(10,20,30);
269 nSum = co2.nData;
270 printf("%d\n", nSum);
271
272 //測試*,這里co2并不是指針哦。只是重載了*的操作符
273 nSum = *co2;
274 printf("%d\n", nSum);
275
276 //測試->,這里也一樣。
277 nSum = co2->nData;
278 printf("%d\n", nSum);
279
280 //測試new new[] delete,
281 //這里沒有測試輸出。單步就知道了。
282 CBaseOperator* pCb1 = new CBaseOperator();
283 CBaseOperator* pCb2 = new CBaseOperator[10];
284 delete pCb1;
285 delete pCb2;
286
287 system("pause");
288 return 0;
289 }
290