第二章面向对象程序设计的概念1第2章面向对象程序设计的概念精讲VC++应用程序是采用C++语言编写的。C++是在C语言的基础上进行改进与扩充,是既面向对象又面向过程的一种混合程序设计语言。传统的程序设计思维方式是基于“算法+数据结构=程序”的模式,在这类程序中,数据和施加于数据的操作(算法过程)总是分离的,所有程序均有一组被动的数据和一组能动的过程所组成。通常把这类程序设计称为面向过程的程序设计,把支持这类程序设计的语言称为面向过程的语言(procedure-orientedlanguage,简称POL)。C语言就是其中的一种。C++保留了C语言的基本语法和流程,C程序几乎都可以在C++环境中不作修改被运行。面向对象程序设计(object-orientedprogramming,简称OOP)将数据及对数据的操作放在一起,作为一相互依存、不可分割的整体来处理,它采用数据抽象和信息隐藏技术。它将对象及对象的操作抽象成一种新的数据类型——类,并且考虑不同对象之间的联系和对象类的重用性。概括为“对象+消息=面向对象的程序”。本章将在C语言基础上对比介绍C++的基本语法,并扩充到面向对象程序设计的基本概念,使读者能够对在VC++应用程序开发中遇到的语法现象有个初步的理解。2.1C++与C的基本语法区别2.1.1一般语法区别1.注释C++支持的注释方法有两种:(1)/*……*/(2)//……“/*……*/”是C语言中所使用的注释方法,在C++中继续延用,一般在连续多行注释时使用。“//……”只能单行注释,进行注释的内容从“//”后的第一个字符直到本行结束。在使用AppWizard生成的MFC应用框架中会默认自动插入大量注释如程序清单2-1所示,“//TODO……”注释行提醒程序员添加代码的位置和通常所作的操作。程序清单2-1:加注释的C++程序BOOLCMainFrame::PreCreateWindow(CREATESTRUCT&cs){if(!CFrameWnd::PreCreateWindow(cs))returnFALSE;//TODO:ModifytheWindowclassorstylesherebymodifying//theCREATESTRUCTcsVC++6简明教程2returnTRUE;}注释一行不要太长,一般60个字符以内(保证在VC++集成编辑环境的可见区域之内),如有超过,建议换行处理。2.常量的定义在C语言中,符号常量的定义是通过宏定义#define来实现的,其实质是字符串替换。例如下面语句定义了一个符号常量PI:#definePI3.1415926在C++中保留#define定义符号常量的方法,但更多地主张采用关键字const来定义符号常量。例如PI的定义可以用下面语句表示:constfloatPI=3.1415926;注意:用关键字const定义的符号常量必须指定其数据类型,而用宏定义的符号常量是没有数据类型的;用关键字const定义的符号常量在编译时为其分配相应的内存空间。规定了符号常量的数据类型,便于编译系统检查参数的数据类型,C++的编译系统检查比C更为严格。3.变量的定义在c语言的函数体中,定义部分和执行语句部分是相对分离的,对局部变量的定义必须出现在函数体或分程序内所有执行语句之前。C++的函数体不再区分定义部分和执行部分,用户可在函数体的任意位置定义一个局部变量。因此一个变量尤其是中间变量,在需要时再定义,这样便于阅读与维护。例如可以在for语句中定义循环变量:intc=1;for(inti=0;i10;i++){c*=2;……}在C++程序中,要注意区分各种变量的作用范围和生命周期,变量的类型有:(1)局部变量(localvariable)在一个函数体内定义的变量,只在本函数范围内有效,在本函数外不能使用。(2)形参变量(formalparameter)向函数传送的变量,同时又能象其他局部变量一样使用。(3)全局变量(globalvariable)在函数体外定义的变量,其有效范围为:从变量定义处开始直到本源文件结束。(4)成员变量(membervariable):在一个类中定义的变量,对类中的所有成员函数都是有效的。在一个继承体系中,根据访问类型和继承类型的不同,对派生类的作用范围会有不同,参见后面章节对继承的讨论。4.强制类型转换C++保留了C语言的显式强制类型转换法:(类型名)表达式同时还提供了函数表示法:类型名(表达式)第二章面向对象程序设计的概念3例如:inti=int(1.35);//给i赋一个初始值函数表示法的函数名只能使用简单类型名称,即int、float、double、char。5.动态变量创建C语言中用函数malloc()动态分配存储空间,用函数dispose()动态释放已分配的存储空间。C++中提供了两个类似该函数的运算符new和delete,它们能完成malloc()和dispose()的功能,而且更为方便和优越。(1)new运算符使用new运算符向内存的“堆”申请某个大小的存储空间,返回存储空间的首地址。空间大小由数据类型决定,分配失败返回空指针。使用new的语句格式如下:指针=new数据类型(初始化值)指针=new数据类型[算术表达式]//分配拥有多个连续空间的动态数组例如:int*pi,*parray;pi=newint(85);//分配一个int型的内存单元,赋初值为85,首地址赋给int型指针piparray=newint[10];//分配10个int型(数组)的内存单元,首地址赋给int型指针parray(2)delete运算符delete运算符用来释放通过new运算符得到的内存空间。使用delete的语句格式如下:delete指针delete[]指针//释放整个数组占用的空间例如:deletepi;//释放p指向的内存单元delete[]parray;//释放parray指向的动态数组内存块,方括号内不要写元素个数6.输入输出语句在C++中继续支持使用C的外部库函数(如printf和scanf等)进行输入输出,以兼容C程序的执行。C++本身引入了流的概念来处理数据的输入输出。所谓的流就是指数据之间的传输操作,包括输入流和输出流。输入流表示数据从载体(如数据文件)或设备(如键盘)流向内存的数据结构,输出流表示数据从内存的数据结构流向载体或设备(如显示器)。流的操作由C++的标准库iostream.h提供,也就是说,如果要使用流操作必须包含库文件“iostream.h”。输入输出流操作包含两个流对象:输出设备cout和输入设备cin;两个操作符:插入操作符“”和抽取操作符“”。进行输出时的语句格式为:cout输出内容[输出内容...];例如:cout”a=”aendl;//endl表示换行,等价于“\n”进行输入时的语句格式为:cin变量1[变量2...];例如:cinxy;程序清单2-2演示了两种不同的输入输出方法的使用:程序清单2-2:C与C++的输入输出比较(1)#include“stdio.h”(2)#include“iostream.h”voidmain()voidmain(){inta,b,sum;{inta,b,sum;VC++6简明教程4printf(“inputab:”);cout“inputab:”;scanf(“%d%d”,&a,&b);cinab;sum=a+b;sum=a+b;printf(“sumis%d\n”,sum);cout”sumis”sumendl;}}cout和cin的优点是可以自动调整输出和输入格式,而不必象printf和scanf都要由使用者一个个指定;另外cout和cin支持用户自定义的数据类型(printf和scanf不支持)。2.1.2指针和引用引用是C++的一个特征,可以把它看作是一个常量指针,并自动被编译器逆向引用。指针是指对象(变量)的地址,而引用是指给对象的地址取一个别名。引用通常应用于函数参数表中作为参数实现双向传值,但也可以作为一个引用变量使用。1.引用变量引用变量的说明方式是:类型&引用名=变量名或对象名;例如:inta;int&b=a;//合法定义引用类型int&c;//错!非法定义引用类型b++;这里b是a合法的引用变量,b是a的别名,不再为b分配空间,a,b共用同一存储单元,对b的操作与对a的操作效果相同,执行b++等同于执行a++。引用变量定义时必须初始化,对此可以这样理解,指针变量的指向可以改变,但作为常量指针的引用,它的指向是不能改变的,所以在创建一个引用时,它必须指向一个特定的合法的存储空间,并且在程序运行过程中不能改变。2.引用参数最常看到引用的场合是在函数的参数表中。C与C++函数参数传送是采用单向传值,形参得到实参的拷贝值。如果需要逆向传值时,即将修改过的参数值反向传递回函数调用处,必须采用传地址的方法,即使用指针变量,直接操作内存空间。而在C++中更好的方法是使用引用参数,即把形参定义为引用变量,编译器会自动地实现逆向传值,引用具有更清晰的语法。程序清单2-3:引用参数举例#includeiostream.hvoidAutoInc1(int*x);voidAutoInc2(int&y);voidmain(){inta(10);AutoInc1(&a);第二章面向对象程序设计的概念5couta=aendl;AutoInc2(a);couta=aendl;}voidAutoInc1(int*x){(*x)++;}voidAutoInc2(int&y){y++;}运行结果:a=11a=12在上面的示例中,定义两个函数AutoInc1和AutoInc2的作用都是增1操作。AutoInc1形参采用的是指针,调用时需传递地址,而AutoInc2形参采用的是引用。可以看到AutoInc2的实现代码更为简单,调用时隐藏性好,即调用代码不能确定是传值还是传地址。2.1.3函数的改进1.函数原型C++中的函数原型其实就是C语言中的函数声明的概念,用于告诉编译系统使用函数的信息,包括函数的返回类型、参数个数和参数类型。函数原型通常放在程序的开始部分或者包含在头文件中,确保编译器在该函数被调用以前就已经“认识”该函数,其语法形式为:返回类型函数名(参数表);例如:char*substring(char*str,intstart,intcount);也可写成:char*substring(char*,int,int);C的类型检查的机制较为薄弱,在很多情况下函数声明都可以省略,但在类型检查更为严格的C++中,所有函数皆必须声明后才可使用,这便是C++所特别要求的函数原型。编译系统对下面情况会给出错误信息:(1)实参和形参的类型不匹配,且实参向形参自动类型转换非法。(2)实参与形参的个数不一致。(3)函数没有按函数的类型返回数据。例如:在C++中main函数前必须指明返回类型为void,否则会出现编译错误,main()函数的一般定义如下:voidmain(){}2.函数重载VC++6简明教程6函数重载是指同一个函数名可以对应着多个函数的实现。函数重载允许一个程序内声明多个名称相同的函数,这些函数通常执行相同的功能,但是带有不同类型、不同数目的参数或不同类型的返回值。例如,要写一个求两个整数之和与两个浮点型数之和的函数如下:intplus(intx,inty){returnx+y;}//整数求和函数doubleplus(doublex,doubley){returnx+y;}//浮点数求和函数以上实现的是两个不同参数类型的重载。这样在调用时可用同一个函数名plus调用,程序会自动完成正确的调用。如:intz=plus(2,3);//调用整数求和函数plusdoublez=plus(2.0,3.5);//调用浮点数求和函数plus编译系统解读函数原型,识别重载。为了使编译系统能确定采用哪一个函