1 基本部分:
2 1、ctrl+f5 调试不运行,会出现press anykey to continue
3 f5 调试
4 2、c++变c,修改Stdafx.h,将#include<stdio.h>替换为#include<iostream>
5 在主函数源文件中加入using namespace std;
6
7 数据类型
8 3、关于字符型变量。
9 input:
10 char a=10;
11 int b=a+'\a';
12 output:b=17。
13 但是字符型的输出不是整数,而是该整数所代表的ASCII码字符。
14 input:
15 char a=65;int b=65;
16 cout<<a<<" "<<b<<endl;
17 output:
18 a 65
19 4、关于常量,可用预处理命令,宏#define,也可用const定义。
20 #define LIYAKUN 130
21 const int liYaKun=130;
22
23 基本结构:
24 5、关于main函数
25 存在int main(int argc,char *argv),arge表示有多少个参数被传递给主函数,argv[]表示参数以字符串数组的形式来传递。
26 不存在void main(),main函数存在Int型的返回值。
27 6、输入输出cin<<,cout>>.
28 cin需要先按下enter键,然后才处理来自键盘的输入。
29
30 运算符:
31 7、C++中存在>=,<=,为关系运算符。
32
33 数组:
34 8、筛选法。可以通过较小的复杂度筛选出两组混杂的数据。
35
36 函数:
37
38 9、声明要放在头文件中,可以使被调函数与所有声明保持一致,如果函数接口发生变化,只需要修改唯一的声明。
39 10、形参在函数调用结束后,形参分配的空间即被释放。
40 11、值传递是无法实现其功能。
41 void swap(int a,int b)
42 {
43 int temp;
44 temp=a;
45 a=b;
46 b=temp;
47 }
48 12、int _tmain(int argc, _TCHAR* argv[])可以兼容main()。
49 13、内联函数inline可以减少函数调用时间,因为inline在编译时,在调用处直接用函数体进行替换。减少了普通函数在掉那样时的栈内存的创建和释放的开销。
50 但是inline不能用循环、If语句,且必须要简洁。
51 #include "stdafx.h"
52 using namespace std;
53 inline int swap(int a,int b);
54 inline int swap(int a,int b)
55 {
56 int temp;
57 temp=a;
58 a=b;
59 b=temp;
60 return 0;
61 }
62
63 int _tmain(int argc, _TCHAR* argv[])
64 {
65 cout<<swap(1,2)<<endl;
66 return 0;
67 }
68
69 指针:
70 14、指针运算符*,在定义的时候称为指针定义符,此时和指针运算符号的意义完全不同。它的作用是表示所声明的变量的数据类型是一个指针。
71 int _tmain(int argc, _TCHAR* argv[])
72 {
73 int iValue=10;
74 int *iPtr=&iValue;
75 cout<<&iPtr<<endl;
76 cout<<iPtr<<endl;
77 cout<<*iPtr<<endl;
78 }
79 output:
80 0071F938
81 0071F938
82 10
83 15、指向函数的指针。实际上是指向存储函数代码的首地址。
84 定义格式如:数据类型 (* 函数指针名)(形参表);
85 注意:为了与返回指针的函数进行区别,第一个括号不能省略。
86 在C++中,赋值的格式如:函数指针名(参数表);
87 注意:函数指针变量不能进行算数运算,毫无意义。
88 16、动态内存的分配方式。
89 堆和栈:1)大小。栈是由系统自动分配的连续的地址空间,1M~2M。堆是通过链表来存储的空闲内存地址,受限于系统的虚拟内存,但远远大于栈的内存。2)栈主要是由局部变量,函参。堆是由程序员自行分配的内存区域。因此,栈的空间由系统自动释放,堆的空间由程序员释放。
90 动态内存的分配:1)可用链表。也就是堆的方式。属于C++的方式。2)可用malloc等函数分配。是自由存储区的方式。属于C的方式。
91
92 比较直观的感觉:当进行数组读写时,动态数组的下标可以用变量来表示。
93 17、C++动态内存的分配。
94 格式:new 类型名(初始值);如:pnValue=new int(3);//通过New分配了一个存放int类型的内存空间,并且将这个内存上写初始值3。
95 注意:如果开辟动态内存,一定要判断是否开辟成功。
96 如:int _tmain(int argc, _TCHAR* argv[])
97 {
98 int *pnValue;
99 pnValue=new int(3);
100 if (pnValue==NULL) exit(1);//如果内存开辟失败,指针为NULL
101 else
102 cout<<"Success!"<<endl;
103 }
104 18、C++动态内存的赋值。
105 当申请空间为数组时,为其赋值不要用指针计算,如“pnValue++;”因为存储地址不是连续的,因此当退回时会出现错误。正确的方法是用过下标或者临时指针来访问动态数组。
106 下标:int _tmain(int argc, _TCHAR* argv[])
107 {
108 int *pnArray=new int[5];
109 pnArray[0]=1;
110 pnArray[1]=2;
111 }
112 临时指针:int _tmain(int argc, _TCHAR* argv[])
113 {
114 int * pnArray=new int[5];
115 int * pnArrayMove=pnArray;
116 * pnArrayMove=1;
117 pnArrayMove++;
118 * pnArrayMove=2;
119 }
120 19、C++初始化动态数组。可用memset函数快速赋值
121 格式:memset(指针名,初始化值,开辟空间的总字节数)
122 如:int _tmain(int argc, _TCHAR* argv[])
123 {
124 long *plArray=new long[4];
125 memset(plArray,0,sizeof(long)*5);//sizeof()不能计算动态内存容量
126 }
127 20、C++动态内存的释放。
128 在C中我们用malloce申请,然后用free释放。在C++中我们用new来申请,用delete释放。同样,在释放以后,我们需要把这些指针赋值NULL。
129 delete a;//a是动态内存变量
130 delate[] a;//a是动态内存数组
131 如:int _tmain(int argc, _TCHAR* argv[])
132 {
133 long *plArray=new long[10];//申请
134 meset(plArray,0x00,sizeof(long)*10);//初始化
135
136 delete[] plArray;//释放
137 plArray=NULL;//赋值NULL
138 }
139
140 引用:
141 21、引用时一个变量或者对象的别名。格式如下:数据类型& 所引用变量或对象名(目标变量或对象)。
142 如:int _tmain(int argc, _TCHAR* argv[])
143 {
144 int nValue;
145 int& rValue=nValue;
146 return 0;
147 }
148 22、当引用作为函数参数出现时的情况。
149 在函数被调用时,由于引用函数作为函数参数出现,因此系统在函数体中直接改变实参,这点跟指针的效果一样。这是引用出现的最常见的情况。
150 如:void swap(int& a,int& b)
151 {
152 int temp;
153 temp=a;
154 a=b;
155 b=temp;
156 }
157
158 int _tmain(int argc, _TCHAR* argv[])
159 {
160 int nValueA=10;
161 int nValueB=20;
162 int& rValueA=nValueA;
163 int& rValueB=nValueB;
164 cout<<nValueA<<","<<nValueB<<endl;
165 swap(rValueA,rValueB);
166 cout<<rValueA<<","<<rValueB<<endl;
167 return 0;
168 }
169 输出:10,20
170 20,10
171 注意:此时,由于函数体改变了引用,。,nValueA=20,nValueB=10。
172 !! 注意:引用的格式,必须为(类名& 实例名)!空格不能乱加。
173 !!类名& 函数体(参数),含义是返回一个类的引用。类的实参返回。
174
175 共用体:
176 23、与结构体类型不同的是,共用体的提点1)同一共用体成员共用一个存储区,存储区大小等于最长字节的成员。2)同一时刻,在一个共用体变量中,只有一个成员起作用。
177
178 字符串:
179 24、sizeof()是操作符,用来返回类型的大小,包括\0,strlen()是函数,用来返回字符串的长度,其中不包括\0。
180 25、cin.getline(数组名称,读取字符数);这个函数读取一行,直至达到换行符,作为字符串的边界。
181
182 类:
183 26、类是C++封装的基本单位,它把数据和函数封装在一起。在定义一个类后,可以声明一个类的变量,即类的对象或者实例。
184 class 类名
185 {
186 …
187 };
188 命名类的时候加前缀"C"。
189 27、在定义类的时候,不为类分配存储空间,不能为类中的数据初始化。
190 28、成员函数。在类中被声明:
191 class 类名{
192 访问控制关键字 返回值类型 成员函数名(参数表);
193 };
194 访问控制关键字:public/private(default)/protected,因为如果不对其进行设置,系统会默认设置,所以在定义时需要定义它的访问控制字。
195 如下:
196 class math(){
197 public: //习惯性先设置公共部分
198 void abs();
199 void add();
200 void mul();
201
202 private:
203 string number_1;
204 string number_2;
205 };
206 29、成员函数在类外实现。
207 class Cmath{
208 void abs();
209 }
210
211 void Cmath::abs(){
212 cout<<"Success!"<<endl;
213 };
214 30、类的实例,也称对象。当实例为非指针时,访问格式为“实例.类成员”;当实例为指针时,范根格式为“实例指针->类成员”。
215 如:
216 math HighMath;
217 math *pHighMath;
218 pHighMath=&HighMath;
219 pHighMath->study();
220 31、静态数据成员。
221 当数据在类中声明为private控制型,但在程序过程中需要对它进行修改。此时可以加static来任何类的实例都可以对其数据进行改变。静态数据不属于任何一个实例,只能通过类名来访问。
222 格式为:int CMath::jingtaishuju=0;
223 不仅可以在main.cpp中访问,也可以在类实现文件中访问。
224 32、静态成员函数。
225 在1)没有实例生成时就需要访问类中的函数信息2)需要所有的类和对象都能访问时,用静态函数。
226 定义格式:
227 static 返回值类型 成员函数名(参数表)
228 访问格式:
229 类名::成员函数名
230
231 构造函数
232 33、构造函数。构造函数实现在实例被创建时利用特定的值去构造实例,将新建的实例初始化为一个特定状态。
233 构造函数属于类里面的一个特殊的类,由系统自动调用,定义时无返回值。
234 格式:
235 类名();//构造函数名与类名相同
236 34、带参数的构造函数。带参数的构造函数需要用实参来进行赋值。
237 !!注意,带参数的构造函数和不带参数的构造函数可以同时存在,相当于构造函数的重载,可8以不带参数赋默认值,也可以带参数,先赋默认值,再赋参数。
238
239 所以!最好在每次定义的时候都要写上不带参数的构造函数!
240
241 这个地方容易产生很多错误,错例如下:
242 Cmath xianxingdaishu;
243 xianxingdaishu.Cmath(1,2,3);
244 //错误!系统会在第一行语句中默认为,使用默认构造函数,因为构造函数是一直存在的。已经产生了实例以后,这样赋值就是不对的。
245 如果构造函数要包含参数,就必须在定义的时候给出实参,实参甚至可以不用定义。
246 改为:
247 Cmath xianxingdaishu(1,2,3);//此处Cmath不是类名,而是构造函数名。
248 格式:
249 类名(初始化参数表);
250 35、拷贝构造函数。
251 用一个实例构造另一个实例,使其初始化为与原实例相同的数据,用拷贝构造函数。可以理解为,构造函数为类的一个特殊函数,拷贝构造函数为构造函数的一个特殊例子。拷贝构造函数与构造函数并存。
252 声明格式:
253 类名(类名& 实例名)//这里的实例名实际上就是参数名,形参
254 实现格式:
255 类名::拷贝构造函数名(类名& 实例参数)//实例参数:形参
256 36、何时应该声明类头文件?
257 只在类.cpp和主函数.cpp中声明 类.h。
258 37、默认拷贝构造函数。
259 如果不写拷贝构造函数,直接在定义的时候对其进行赋值初始化:
260 如:
261 //CMath.h
262 class CMath{
263 public:
264 CMath(string strMathName,string trMathLength,float strMathLevel);//构造函数
265 //CMath(CMath& MathModel);//拷贝构造函数
266 void SetMathName();
267 void SetMathLength();
268 void SetMathLevel();
269 void ShowMathName();
270 void ShowMathLength();
271 void ShowMathLevel();
272 private:
273 string m_strMathName;
274 string m_strMathLength;
275 float m_fMathLevel;
276 };
277
278 //CMath.cpp
279 CMath::CMath(string MathName,string MathLength,float MathLevel){
280 m_strMathName=MathName;
281 m_strMathLength=MathLength;
282 m_fMathLevel=MathLevel;
283 };
284 //主函数
285 #include "stdafx.h"
286 using namespace std;
287 #include "CMath.h"
288 #include "string.h"
289 int _tmain(int argc, _TCHAR* argv[])
290 {
291 CMath MathModel1("FFT","fifty",8);
292 CMath MathModel2=MathModel1;//调用了默认的拷贝构造函数
293 MathModel2.ShowMathName();
294 MathModel2.ShowMathLength();
295 MathModel2.ShowMathLevel();
296 }
297 实际相当于,将所有的非静态变量都赋值给了新定义的实例。
298 38、默认拷贝构造函数的局限。
299 1)默认,是完全相同的赋值,实际上很多时候是不必要的。
300 2)无法实现对动态内存进行拷贝。
301 39、fatal error LNK1120: 1 个无法解析的外部命令。
302 因为在头文件已经声明,但是在CPP文件中没有实现。
303 40、深拷贝。由于存在默认拷贝构造函数的局限性,尤其是在对类中存在动态内存时无法拷贝,深拷贝能完成动态内存的拷贝。
304 原理,在类中增加深拷贝函数,函数实现中先进行另外一个动态内存申请,然后再赋值。
305 如:
306 //CMath.h
307 class CMath{
308 public:
309 CMath(string strMathName,string trMathLength,float strMathLevel);//构造函数
310 CMath(CMath& MathModel);//拷贝构造函数,深拷贝
311 void SetMathName();
312 void SetMathLength();
313 void SetMathLevel();
314 void ShowMathName();
315 void ShowMathLength();
316 void ShowMathLevel();
317 private:
318 string * m_strMathName;//在实现函数中对其进行赋初值,new string
319 string m_strMathLength;
320 float m_fMathLevel;
321 };
322 //CMath.cpp
323 CMath::CMath(string MathName,string MathLength,float MathLevel){
324 m_strMathName=new string;//动态赋初值
325 *m_strMathName=MathName;
326 m_strMathLength=MathLength;
327 m_fMathLevel=MathLevel;
328 };
329 CMath::CMath(CMath& MathModel){//建立拷贝构造函数
330 m_strMathName=new string;//再开动态赋初值
331 *m_strMathName=*MathModel.m_strMathName;
332 m_strMathLength=MathModel.m_strMathLength;
333 m_fMathLevel=MathModel.m_fMathLevel;
334 };
335 //主函数
336 int _tmain(int argc, _TCHAR* argv[])
337 {
338 CMath MathModel1("FFT","fifty",8);
339 CMath MathModel2(MathModel1);//引用已定义的实例
340 MathModel2.ShowMathName();
341 MathModel2.ShowMathLength();
342 MathModel2.ShowMathLevel();
343 }
344 41、析构函数。对当前分配的资源进行清理。
345 声明语法格式:~类名()//virtual ~CMath();//虚析构函数
346 实现如:CMath::~CMath()
347 {
348 delete m_strMathName;
349 m_strMathName=NULL;
350 }
351 注意:析构函数是默认存在的,程序员需要设置对其类中包含的动态变量进行析构。
352 !!在主程序中不需要调用析构函数,因为系统会在实例的生存期结束以后自动调用类中的析构函数。
353 !!一旦声明了析构函数,就必须对析构函数进行实现!
354 42、类的组合。
355 类的组合其实就是在类的声明里面嵌套其他的类。类的组合主要问题在于初始化,因为要同时对类的内嵌对象进行初始化。
356 格式:类名::类名(形参表):内嵌对象1(形参表),内嵌对象2(形参表)
357 {
358 }
359 //这个地方还有不清楚的地方。
360
361 友元函数和友元类
362 43、友元就是在需要访问多个类的私有参数时,用到了友元。但是在可以利用关键字friend来修饰。包括友元函数,友元类(类中所有函数都是友元函数)。
363 声明格式:friend 返回值类型 函数名(参数);
364 //EleSchStu.h
365 class EleSchStu{
366 public:
367 void SetName(EleSchStu &);
368 virtual ~EleSchStu();
369 //设置友元函数来测试名字长度,不一定非要是引用型
370 friend void CheckNameLength(EleSchStu &);
371 private:
372 string strName;
373 static const int MAX_NAME_LEN;
374 double score1;
375 double score2;
376 double score3;
377 };
378 //EleSchStu.cpp
379 #include "stdafx.h"
380 using namespace std;
381 #include "EleSchStu.h"
382 #include <string>
383
384 void EleSchStu::SetName(EleSchStu &xiaoming){
385 string str;
386 cout<<"input the name:"<<endl;
387 cin>>str;
388 xiaoming.strName=str;
389 };
390
391 EleSchStu::~EleSchStu(){
392
393 };
394 void CheckNameLength(EleSchStu &xiaoming){
395 if ((xiaoming.strName.length())>xiaoming.MAX_NAME_LEN)
396 {
397 cout<<"输入的名字长度太长了!"<<endl;
398 }
399 };
400 //主函数
401 const int EleSchStu::MAX_NAME_LEN=3;
402 const int JuniorSchStu::MAX_NAME_LEN=3;
403 int _tmain(int argc, _TCHAR* argv[])
404 {
405 EleSchStu xiaoming;
406 xiaoming.SetName(xiaoming);
407 CheckNameLength(xiaoming);
408 return 0;
409 }
410
411 44、include <string>
412
413 重载----重载函数和运算符重载
414 45、重载函数。允许用同一个函数名定义多个函数,简化程序设计。从而使一个函数名就可以完成一系列相关的任务。
415 重载函数如下一组:
416 long abs(long);
417 double abs(double);
418 注意!只有是返回类型、参数类型、参数个数、参数顺序上有所不同!不能仅仅是返回值不同。否则不能识别为重载函数。
419 46、运算符重载。(operator)
420 对已有的运算符赋予更多的含义。如:使同一个运算符作用于不同类型的数据。(运算符:+,-,*,/,%,new等)
421 当运算符重载为成员函数时://关键字 operator
422 格式:函数类型 operator 运算符 (形参表)
423 {
424 函数体;
425 }
426 为类的友元函数时:
427 格式: friend 函数体 operator 运算符(形参表)
428 {
429 函数体:
430 }
431 47、转换运算符的重载。
432 当用户自定义的数据类型也需要支持数据的转换时,需要用重载转换运算符。而且不能是友元函数。
433 格式如下:
434 operator 类型名();//返回类型其实就是类型名,所以不需要制定返回类型。
435 48、赋值运算符的重载。
436 关于重载的实例:
437 需求:写出复数的+、-、*,用类的重载实现,分别用三个友元函数实现运算,能够显示原数据,最终分别用实例来验证三个算法。
438 //CComplex.h
439 #include <iostream>
440 using namespace std;
441
442 //CComplex.h
443 class CComplex
444 {
445 public:
446 CComplex();//不带参数的构造函数
447 CComplex(double temp_real,double temp_imag);//含参的构造函数
448 virtual ~CComplex();
449 void show();
450 private:
451 double real;
452 double imag;
453 friend CComplex operator + (CComplex a,CComplex b);
454 friend CComplex operator - (CComplex a,CComplex b);
455 friend CComplex operator * (CComplex a,CComplex b);
456
457 };
458 //CComplex.cpp
459 #include <iostream>
460 using namespace std;
461 #include "stdafx.h"
462 #include "CComplex.h"
463
464 CComplex::CComplex()
465 {
466 cout<<"默认构造函数……"<<endl;
467 real=0;
468 imag=0;
469 }
470 CComplex::CComplex(double temp_real,double temp_imag)
471 {
472 real=temp_real;
473 imag=temp_imag;
474 }
475 CComplex::~CComplex()
476 {
477 }
478
479 void CComplex::show()
480 {
481 cout<<"("<<real<<","<<imag<<")"<<endl;
482 }
483
484 CComplex operator + (CComplex a,CComplex b)
485 {
486 CComplex plus;
487 plus.real=a.real+b.real;
488 plus.imag=a.imag+b.imag;
489 return plus;
490 }
491
492 CComplex operator - (CComplex a,CComplex b)
493 {
494 CComplex minus;
495 minus.real=a.real-b.real;
496 minus.imag=a.imag-b.imag;
497 return minus;
498 }
499
500 CComplex operator * (CComplex a,CComplex b)
501 {
502 CComplex mult;
503 mult.real=a.real*b.real-a.imag*b.imag;
504 mult.imag=a.real*b.imag+a.imag*b.real;
505 return mult;
506 }
507 //重载.cpp
508 #include "stdafx.h"
509 #include "CComplex.h"
510
511 int _tmain(int argc, _TCHAR* argv[])
512 {
513 CComplex p1(1.0,2.0);
514 CComplex p2(3.0,4.0);
515 CComplex p3,p4,p5;
516 p3=p1+p2;
517 p4=p1-p2;
518 p5=p1*p2;
519 p1.show();
520 p2.show();
521 cout<<"+:";
522 p3.show();
523 cout<<"-:";
524 p4.show();
525 cout<<"*:";
526 p5.show();
527 return 0;
528 }
529
530 继承和派生:
531 49、派生类。
532 派生会接收基类中除了构造函数和析构函数以外的所有成员。也可以改造基类成员,对其进行覆盖和重载,也可以增加新的类成员。
533 格式:
534 class 派生类名:继承方式 基类名1,继承方式 基类名2…
535 //!继承只有一个冒号!
536 {
537 成员声明;
538 }
539 // 继承方式的关键字:public/protected/private(default)
540 50、继承中的访问控制。
541
542 为public继承时,基类中保护成员和公有成员在派生类中不变。
543 为private继承时,基类中保护成员和公有成员在派生类中变为私有成员。(由于会中止类的继续派生,因此Private继承基本没用)
544 为protected继承时,基类中保护成员和公有成员在派生类中变为保护成员。(在protected继承中,基类中的protected成员在基类的派生中的访问权限还是protected;在private继承中,基类中的protected成员在基类的派生中访问权限是private,因此在下一级的派生中,就无法访问基类的成员!!因此protected继承更加适合多层派生!!)
545
546 !!所有的继承均无法访问基类中的私有成员。
547 !!!Protected 与Public有区别!!protected是保护的,只有他自身或者继承他的类可以用,public是共有的,在静态下所有类都可以通过类名打点调用,不是静态下,可以用类对象点去调用。
548 !!!???
549
550 如例:
551 #include "stdafx.h"
552 //Point.h
553 class CPoint
554 {
555 public:
556 //CPoint();//构造函数
557 virtual ~CPoint();
558 void InitPoint(double x,double y);
559 double GetX();
560 double GetY();
561 protected:
562 double X,Y;
563 };
564 #endif
565 //Linesegment.h
566 #include "stdafx.h"
567 #include "CPoint.h"
568 class CLinesegment:protected CPoint
569 {
570 public:
571 //CLinesegment();
572 virtual ~CLinesegment();
573 void InitLinesegment(double x,double y,double length);
574 double GetX();//可以直接访问基类的保护成员
575 double GetY();//可以直接访问基类的保护成员
576 double GetLength();
577 protected:
578 //double X,Y;
579 double Length;
580 };
581 //CPoint.cpp
582 #include "stdafx.h"
583 #include "CPoint.h"
584 //#include "Linesegment.h"
585 CPoint::~CPoint()
586 {
587 };
588 void CPoint::InitPoint(double x,double y)
589 {
590 this->X=x;
591 this->Y=y;
592 };
593 double CPoint::GetX()
594 {
595 return this->X;
596 };
597 double CPoint::GetY()
598 {
599 return this->Y;
600 };
601 //Linesegment.cpp
602 #include "stdafx.h"
603 #include "CPoint.h"
604 #include "Linesegment.h"
605 CLinesegment::~CLinesegment()
606 {
607 };
608 void CLinesegment::InitLinesegment(double x,double y,double length)
609 {
610 InitPoint(x,y);//调用基类的函数
611 this->Length=length;
612 };
613 double CLinesegment::GetX()//可以直接访问基类的保护成员?????,因为继承类中不存在x,y的成员变量
614 {
615 return this->X;
616 };
617 double CLinesegment::GetY()//可以直接访问基类的保护成员?????,因为继承类中不存在x,y的成员变量
618 {
619 return this->Y;
620 };
621 double CLinesegment::GetLength()
622 {
623 return this->Length;
624 };
625 //主函数
626 // 保护继承.cpp : 定义控制台应用程序的入口点。
627 #include "stdafx.h"
628 #include "CPoint.h"
629 #include "Linesegment.h"
630
631 int _tmain(int argc, _TCHAR* argv[])
632 {
633 CLinesegment L1;
634 L1.InitLinesegment(0,0,5);
635 cout<<"("<<L1.GetX()<<","<<L1.GetY()<<","<<L1.GetLength()<<")"<<endl;
636 return 0;
637 }
638 51、派生类的构造函数。
639 由于派生类不能继承基类的构造函数,因此需要定义构造函数。
640 声明格式: 构造函数(参数);
641 实现格式:派生类名::派生类名(参数):继承方式1 基类名1(参数表1),继承方式2 基类名2(参数表2)...,内嵌实例名1(参数表1)//内嵌就是在派生类中又定义的类
642 {
643 派生类构造函数函数体;
644 }
645 !如果基类中没有自定义的构造函数,就将基类名(参数表)省略。所有都可以省略时,可以用生两侧派生类构造函数的成员初始化列表。
646 52、派生类的析构函数。
647 直接析构。
648 53、派生类成员的标识和访问。
649 格式:派生类实例名.基类名::成员名;
650 派生类实例名.基类名::成员函数名(函数表);
651 ::是作用域分辨符,可以用于限定要访问的成员所在的类的名称。
652 !::不可以嵌套使用,比如:实例A.C1::C2::fun();错误!只能在C2函数中声明fun1(){},再调用fun()。
653 54、虚基类:解决二义性的问题。
654 声明格式:class 类名: virtual 继承方式 基类名。
655 实例:定义一个车的基类,有最大速度、质量成员变量,及一些成员函数;派生出自行车类和汽车类,自行车有高度等成员变量,汽车有座位数等成员变量;从自行车和汽车派生出摩托车类。要求观察析构函数的执行和继承中,把车类设成虚基类和不设为虚基类的区别。
656 //vehicle.h
657 #ifndef _vehicle_h_
658 #define _vehicle_h_
659 #include "stdafx.h"
660 class CVehicle
661 {
662 public:
663 CVehicle();
664 CVehicle(int speed,int weight);
665 virtual ~CVehicle();
666 protected:
667 int Speed;
668 int Weight;
669 };
670 #endif
671 //vehicle.cpp
672 #include "stdafx.h"
673 #include "vehicle.h"
674
675 CVehicle::CVehicle()
676 {
677 cout<<"CVehicle类的实例的构造函数生成!"<<endl;
678 };
679 CVehicle::CVehicle(int speed,int weight)
680 {
681 this->Speed=speed;
682 this->Weight=weight;
683 }
684 CVehicle::~CVehicle()
685 {
686 cout<<"CVehicle类的实例的析构函数生成!"<<endl;
687 };
688 //bike.h
689 #ifndef _bike_H_
690 #define _bike_H_
691 #include "stdafx.h"
692 #include "vehicle.h"
693
694 class CBike:virtual public CVehicle
695 {
696 public:
697 CBike();
698 CBike(int height);
699 virtual ~CBike();
700 protected:
701 int height;
702 };
703 #endif
704 //bike.cpp
705 #include "stdafx.h"
706 #include "vehicle.h"
707 #include "bike.h"
708
709 CBike::CBike()
710 {
711 cout<<"CBike类的实例的构造函数生成!"<<endl;
712 };
713 CBike::CBike(int height)
714 {
715 this->height=height;
716 }
717 CBike::~CBike()
718 {
719 cout<<"CBike类的实例的析构函数生成!"<<endl;
720 };
721 //car.h
722 #ifndef _car_H_
723 #define _car_H_
724
725 #include "stdafx.h"
726 #include "vehicle.h"
727
728 class CCar:virtual protected CVehicle
729 {
730 public:
731 CCar();
732 CCar(int seat);
733 virtual ~CCar();
734 protected:
735 int seat;
736 };
737 #endif
738 //car.cpp
739 #include "stdafx.h"
740 #include "vehicle.h"
741 #include "car.h"
742
743 CCar::CCar()
744 {
745 cout<<"CCar类的实例的构造函数生成!"<<endl;
746 };
747 CCar::CCar(int seat)
748 {
749 this->seat=seat;
750 };
751 CCar::~CCar()
752 {
753 cout<<"CCar类的实例的析构函数生成!"<<endl;
754 };
755 //motor.h
756 #ifndef _motor_H_
757 #define _motor_H_
758
759 #include "stdafx.h"
760 #include "vehicle.h"
761 #include "bike.h"
762 #include "car.h"
763
764 class CMotor: public CBike,public CCar
765 {
766 public:
767 CMotor();
768 CMotor(int speed, int weight, int height, int seat, int money):CVehicle(speed,weight),CCar(seat),CBike(height)
769 {
770 this->money=money;
771 };
772 virtual ~CMotor();
773 void showMotor();
774 protected:
775 int money;
776 };
777 #endif
778 //motor.cpp
779 #include "stdafx.h"
780 #include "vehicle.h"
781 #include "car.h"
782 #include "bike.h"
783 #include "motor.h"
784
785 CMotor::CMotor()
786 {
787 cout<<"构造CMotor类的实例!"<<endl;
788 }
789 CMotor::~CMotor()
790 {
791 cout<<"CMotor类的实例的析构函数生成!"<<endl;
792 }
793 void CMotor::showMotor()
794 {
795 void showCar();
796 void showBike();
797 //showVehicle();
798 cout<<"speed="<<this->Speed<<endl;
799 cout<<"weight="<<this->Weight<<endl;
800 cout<<"height="<<this->height<<endl;
801 cout<<"seat="<<this->seat<<endl;
802 cout<<"money="<<this->money<<endl;
803 }
804 //主函数
805 // 继承.cpp : 定义控制台应用程序的入口点。
806 #include "stdafx.h"
807 #include "vehicle.h"
808 #include "car.h"
809 #include "bike.h"
810 #include "motor.h"
811
812 int _tmain(int argc, _TCHAR* argv[])
813 {
814 int a=200,b=50000,c=1,d=4,e=100000;
815 CMotor motor(a,b,c,d,e);
816 motor.showMotor();
817 return 0;
818 }
819 55、多态性
820 指同一个函数,根据处理的对象不同,所调用的函数实现不同。通过虚函数来实现。
821 56、虚函数。
822 当基类定义的一个函数,派生类对函数进行了重载。重载以后,程序无法确定到底是哪个类调用了函数。
823 当然,我们可以用作用域运算符来确定到底是哪个调用了。但有的情况下,程序会不知道:声明的函数到底调用了基类的对象,还是派生类的对象。因此,程序会默认调用了基类的对象,导致逻辑错误。
824 !一句话概括:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。
825
826 虚函数定义格式:
827 virtual 函数返回格式 函数名()
828 {
829 };
830 调用格式():
831 Class CA
832 {
833 public:
834 …
835 virtual float xuhanshu()
836 {};
837 }
838
839 Class CB:public CA
840 {
841 public:
842 ...
843 virtual float xuhanshu()
844 {};
845 }
846 //mian.cpp
847
848 float get_xuhanshu(CA& temp)//注意参数类型
849 {
850 return temp.xuhanshu();
851 }
852 main()
853 {
854 CA test1;
855 CB test2;
856 get_xuhanshu(test1);//系统识别调用CA中的实例
857 get_xuhanshu(test2);//系统识别调用CB中的实例
858 }
859
860 57、纯虚函数和抽象类。
861 纯虚函数就是在一般的虚函数定义的后面加“=0”,本质上是将指向函数体的指针置零。
862 抽象类是带有纯虚函数的类。抽象类的作用是为了建立类族的共同接口。抽象类不能实例化,但抽象类的派生类可以实例化。
863 抽象类中的纯虚函数可以在主函数中实现,然后它的引用可以被任何派生类的实例调用。
864 如:
865 class A
866 {
867 ...
868 virtual void display()=0;
869 ...
870 }
871 class B:A
872 {
873 ...
874 virtual void display()
875 { cout<<"class B"<<endl;};
876 ...
877 }
878 class C:B
879 {
880 ...
881 virtual void display()
882 { cout<<"class C"<<endl;};
883 ...
884 }
885 //main.cpp
886 void display(A& temp)
887 {
888 temp.display();
889 }
890
891 void main()
892 {
893 B b;
894 C c;
895 display(b);//相当于在主函数中声明了一个函数,只要是A类族的参数都可以调用。
896 display(c);
897 }
898 output:
899 class B
900 class C
901
902 例子:抽象类shape,5个派生类,circle,square,rectangle,trapezoid,triangle,用虚函数分别计算几个图形面积,并求它们的和。用基类指针数组,使它的每一个元素指向一个派生类对象。
903 //shape.h
904 #ifndef _Shape_H_
905 #define _Shape_H_
906 #include "stdafx.h"
907 class Shape
908 {
909 public:
910 virtual void show(){};
911 virtual double area()=0;//只有含返回参数的成员函数,才能当作纯虚函数
912 //主要当作一个接口
913 };
914 #endif
915 //circle.h
916 #include "stdafx.h"
917 #include "shape.h"
918 #include <math.h>
919
920 class circle:public Shape
921 {
922 public:
923 circle(double temp_r)
924 {
925 r=temp_r;
926 };
927 virtual ~circle(){};
928 void show()
929 {
930 double temp;
931 temp=area();
932 cout<<"this is circle! the area is "<<temp<<endl;
933 };
934 double area()
935 {
936 double temp;
937 temp=r*r*3.14;
938 return temp;
939 };
940 protected:
941 double r;
942 };
943 //square.h
944 #include "stdafx.h"
945 #include "shape.h"
946 #include <math.h>
947 class square:public Shape
948 {
949 public:
950 square(double l)
951 {
952 this->l=l;
953 };
954 virtual ~square(){};
955 double area()
956 {
957 double temp;
958 temp=this->l*this->l;
959 return temp;
960 }
961 void show()
962 {
963 double temp=this->area();
964 cout<<"this is square!,the area is "<<temp<<endl;
965 }
966 protected:
967 double l;
968 };
969
970 //main.cpp
971 // 虚函数.cpp : 定义控制台应用程序的入口点。
972 #include "stdafx.h"
973 #include "shape.h"
974 #include "circle.h"
975 #include "square.h"
976 #include <math.h>
977
978 int _tmain(int argc, _TCHAR* argv[])
979 {
980 circle c(5);
981 square s(5);
982 Shape *p[2];
983 p[0]=&c;//虚基类的实例可以指向派生类的引用
984 p[1]=&s;
985 p[0]->show();
986 p[1]->show();
987 return 0;
988 }
989 输入输出体系:
990 58、流。
991 流其实形象的比喻了C++中数据传输的过程。
992 流操作包含了许多类。类名包括:ios,istream,ostream...
993 59、流格式化输出。
994 如果需要控制流输出的格式,如果要控制流输出的格式。一种用流格式控制符;另一种是利用流类的相关成员函数进行控制。
995 1)流控制符:
996 需要定义头文件<iomanip>;
997 应用如:
998 int a=15;
999 cout<<"十进制"<<dec<<a<<endl;//以十进制形式输出整数a
1000 cout<<"十六进制"<<hex<<a<<endl;
1001 double pi=3.14;
1002 cout<<"指数形式"<<setiosflags(ios::scientific)<<setprecision(8);
1003 //不需要记住,只需要知道按指数形式输出,8位小数
1004 2)流控制成员函数。具体应用要具体查文档。
1005 60、文件操作。
1006 首先需要定义输入输出文件流对象头文件<fstream>。
1007 声明对象:
1008 ifstream file_in;//建立输入文件流对象
1009 ofstream file_out;//建立输出文件流对象
1010 fstream file_inout;//建立输入输出文件流对象
1011 构造函数:
1012 ifstream::ifstream(const char*,int=ios::in,int=filebuf::openprot);
1013 ofstream::ofstream(congst char*,int=ios::out,int=filebuf::openprot);
1014 fstream::fstream(cont char*,int,int=filebuf::operprot);
1015 调用构造函数如:
1016 ofstream file_out("C:\\a_out.dat",ios::out|ios::binary);//以二进制方式打开输出文件。
1017 61、检查是是否打开文件。关闭文件。
1018 bool fail();//失败返回true,成功返回false。
1019 类中的成员函数close():
1020 void close();
1021 62、关于写文件。
1022 分为读写字符型文件(主要是读写到.txt)和二进制文件(都写到.dat)。
1023 具体应用如下。
1024 // 打开文件.cpp : 定义控制台应用程序的入口点。
1025 #include "stdafx.h"
1026 #include <iostream>
1027 #include <fstream>
1028 using namespace std;
1029
1030 int _tmain(int argc, _TCHAR* argv[])
1031 {
1032 //打开文件!
1033 ofstream file_out;//定义打开文件类
1034
1035 file_out.open("C:\\c++.txt",ios::out|ios::app);//打开文件,用于数据输出,从文件中写数据,app是以数据追加方式打开。
1036 if(file_out.fail()) //如果文件打开失败,则显示出错信息。
1037 {
1038 cerr<<"文件 c++.txt 打开失败!"<<endl;
1039 return 1;
1040 }
1041
1042 //输出到文件!
1043 //利用插入操作符进行输出
1044 file_out<<"wo cao ni ma!"<<endl;
1045 file_out<<"我草泥马!"<<endl;
1046
1047 //利用put()进行输出
1048 char a = '!';
1049 file_out.put(a);
1050
1051 //文件的内容输入到内存!
1052 //利用提取操作符
1053 ifstream file_in;//定义打开文件类
1054
1055 file_in.open("C:\\c++.txt",ios::in);//打开文件,用于数据输入,从文件中读数据)
1056 if(file_in.fail()) //如果文件打开失败,则显示出错信息。
1057 {
1058 cerr<<"文件 c++.txt 打开失败!"<<endl;
1059 return 1;
1060 }
1061
1062 char nRead = 0;
1063 while (!file_in>>nRead)//读取字符,注意,提取的时候是忽略换行和空格字符的
1064 {
1065 cout<<nRead<<" ";//" "即为输出字符
1066 }
1067
1068
1069 while (!file_in.eof())//读取字符,注意,提取的时候是包括换行和空格字符的
1070 //eof()用于判断指针是否已经到文件的末尾了,当返回ture时,已经到达文件的尾部
1071 {
1072 file_in.get(nRead);
1073 cout<<nRead;
1074 }
1075
1076 file_out.close();//关闭文件
1077 file_in.close();
1078
1079 return 0;
1080 }
1081 实例:定义一个结构体,通过键盘输入学生的信息并保存到磁盘stud.dat文件中,并从中读出来显示在屏幕上。
1082 // 二进制文件操作.cpp : 定义控制台应用程序的入口点。
1083 #include "stdafx.h"
1084 #include <iostream>
1085 using namespace std;
1086 #include <string>
1087 #include <fstream>
1088
1089 struct Student
1090 {
1091 char name[20];
1092 int age;
1093 char No[20];
1094 char sex[20];
1095 };
1096 int _tmain(int argc, _TCHAR* argv[])
1097 {
1098 Student stu[2];
1099 int i;
1100 int j=0;
1101 for(i=0;i<2;i++)
1102 {
1103 cout<<"please insert your name:";
1104 cin>>stu[i].name;
1105 cout<<"please insert your age:";
1106 cin>>stu[i].age;
1107 cout<<"please insert your Number:";
1108 cin>>stu[i].No;
1109 cout<<"please insert your sex:";
1110 cin>>stu[i].sex;
1111 }
1112 ofstream put_in("C:\\c++.dat",ios::out|ios::binary);//打开二进制文件
1113 if (!put_in) //判断是否打开成功
1114 {
1115 cerr<<"C:\\c++.dat can't open it..."<<endl;
1116 exit(1);
1117 }
1118 for(i=0;i<2;i++)
1119 {
1120 put_in.write((char *) &stu[i],sizeof(stu[i]));//文件写入的时候用的是指针,而不是内容
1121 }
1122 put_in.close();
1123
1124 ifstream put_out("C:\\c++.dat",ios::out|ios::binary);//打开二进制文件
1125 if (!put_out)
1126 {
1127 cerr<<"C:\\c++.dat can't open it..."<<endl;
1128 exit(1);
1129 }
1130 for(i=0;i<2;i++)
1131 {
1132 put_out.read((char *) &stu[i],sizeof(stu[i]));//成语按函数read()来读二进制文件
1133 }
1134 put_out.close();
1135 for(i=0;i<2;i++) //输出!
1136 {
1137 cout<<"the "<<i+1<<" name:";
1138 cout<<stu[i].name<<endl;
1139 cout<<"the "<<i+1<<" age:";
1140 cout<<stu[i].age<<endl;
1141 cout<<"the "<<i+1<<" Number:";
1142 cout<<stu[i].No<<endl;
1143 cout<<"the "<<i+1<<" sex:";
1144 cout<<stu[i].sex<<endl;
1145 }
1146 return 0;
1147 }
1148
1149 63、异常。
1150 try(){throw 类型名;};
1151 catch(类型变量)
1152 {
1153 };
1154 做过选课系统的应该比较熟悉。
1155 直接上实例。
1156 //MyException.h
1157 #include "stdafx.h"
1158 class CMyException
1159 {
1160 public:
1161 CMyException(string msg)
1162 {
1163 err_msg=msg;
1164 };
1165 virtual ~CMyException()
1166 {
1167
1168 };
1169 void show()
1170 {
1171 cerr<<err_msg<<endl;
1172 }
1173 protected:
1174 string err_msg;
1175 };
1176 //main.cpp
1177 // C++速成.cpp : 定义控制台应用程序的入口点。
1178 //
1179
1180 #include "stdafx.h"
1181 #include "MyException.h"
1182 int _tmain(int argc, _TCHAR* argv[])
1183 {
1184 int type;
1185 cout<<"plese insert the number of exception:1.int 2.float 3.double 4.selfdefine"<<endl;
1186 cin>>type;
1187 try{
1188 switch(type)
1189 {
1190 case 4:
1191 throw CsMyException("wrong!");//抛出自定义类异常
1192 break;
1193 case 1:
1194 throw 1;//整形
1195 break;
1196 case 2:
1197 throw 1.2f;//float
1198 break;
1199 case 3:
1200 throw 1.23;//doubule
1201 break;
1202 default:
1203 break;
1204 }
1205 }
1206
1207 catch(CMyException a)
1208 {
1209 a.show();
1210 }
1211 catch(int b)
1212 {
1213 cerr<<"error int!";
1214 }
1215 catch(float c)
1216 {
1217 cerr<<"error float!";
1218 }
1219 catch(double d)
1220 {
1221 cerr<<"error double!";
1222 }
1223 return 0;
1224 }
1225 API编程:
1226 64、API:Windows Application Programming Interface.
1227 windows底层->win32 API函数->windows应用程序
1228 句柄:本身为内存中一个占有4个字长的数值,用于标识应用程序中不同对象和相同对象的不同实例。句柄与普通指针的区别在于,指针包含的是引用对象的内存地址,而句柄则是由系统所管理的引用标识,该标识可以被系统重新定位到一个内存地址上。这种间接访问对象的模式增强了系统对引用对象的控制。
1229
1230
1231
1232