C++的新手入门答疑

   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 12int _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 24sizeof()是操作符,用来返回类型的大小,包括\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  

 

posted @ 2013-08-22 21:19  友琼  阅读(767)  评论(0编辑  收藏  举报