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