C程序设计教程与实验指导_第1页
C程序设计教程与实验指导_第2页
C程序设计教程与实验指导_第3页
C程序设计教程与实验指导_第4页
C程序设计教程与实验指导_第5页
已阅读5页,还剩306页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C++语言程序设计杨国兴张东玲彭涛第1章C++与面向对象程序概述1.1程序设计语言的开展1.2面向对象程序设计的特点1.3C++语言的特点1.4简单的C++程序1.5VisualC++6.0编程环境简介1.1程序设计语言的开展1.1.1机器语言由计算机硬件系统可以识别的二进制指令组成的语言称为机器语言。1.1.2汇编语言汇编语言是用人们比较习惯的符号来代替机器指令〔如用ADD来代替001表示加法操作〕。汇编语言和机器语言都属于低级语言,其语言的结构都是以面向机器的指令序列形式为主,与人的习惯语言方式距离较远,因此编写的程序可读性及可维护性差、代码冗长、不适于编写大规模程序,同时程序依赖于机器、可移植性差。第1章C++与面向对象程序概述1.1程序设计语言的开展1.1.3高级语言与汇编语言和机器语言相比,高级语言更接近人类的自然语言,程序可以采用具有一定涵义的数据命名和容易理解的语句编写。高级语言的开展经历了高级语言编程的初级阶段、结构程序设计阶段和面向对象程序设计阶段。结构化程序设计的特点:自顶向下、逐步求精。他是一种面向过程的程序设计方法,将程序分解为模块,使得数据和数据处理过程别离。面向对象的程序设计方法将数据和处理数据的过程封装在一起,形成一个有机的整体〔即类〕,更符合人们通常的思维习惯,使得开发的软件产品易重用,易修改,易测试,易维护,易扩充。第1章C++与面向对象程序概述

返回1.2面向对象程序设计的特点1.2.1面向对象程序设计的根本概念1.类:具有相同特性〔数据元素〕和相同行为〔函数〕的对象的集合,如汽车类、人类等。2.对象:是现实世界实际存在的事物,是类的一个具体实例。面向对象程序设计中的对象是系统中用来描述客观事物的一个实体,它是用来构成系统的一个根本单位。对象由一组属性和一组行为构成。3.属性:类中的特性〔数据〕称为类的属性,如汽车的颜色、书的作者、书名等都是属性。4.方法:类中的行为〔函数〕称为类的方法,如汽车的刹车、加速行为等都是方法。第1章C++与面向对象程序概述1.2面向对象程序设计的特点1.2.2面向对象程序设计的特点1.封装和数据隐藏:面向对象程序设计中,通过创立类〔包含属性与方法〕实现封装和数据隐藏。如创立汽车类,将汽车的内部数据和方法封装在一起,实现数据隐藏,使用汽车类的程序员并不需要掌握汽车类内部的具体细节,只需要了解汽车类的外部接口就可以了,为程序代码的重用提供了方便。2.继承:是指在已经存在类的根底上,产生一个新的类,新类继承已有类的属性和方法,并可以增加自己新的属性和方法。类的继承也是实现代码重用的有效手段。3.多态:通过函数重载实现的静态多态和虚函数实现的动态多态能够使得程序中的相同代码表现出不同的行为。第1章C++与面向对象程序概述

返回1.3C++语言的特点C++语言是在C语言的根底上开展而来,同时它又支持面向对象的程序设计,它主要具有以下特点:1.继承自C语言的优点:语言简洁、紧凑,使用方便、灵活;拥有丰富的运算符;生成的目标代码质量高,程序执行效率高;可移植性好等。2.对C语言进行的改进:编译器更加严格,引入引用的概念,引入const常量和内联函数,取代宏定义等。3.同时支持面向过程和面向对象的方法:在C++环境下既可以进行面向对象的程序设计,也可以进行面向过程的程序设计。因此它也具有数据封装和隐藏、继承和多态等面向对象的特征。第1章C++与面向对象程序概述

返回1.4简单的C++程序1.4.1cout标准输出

cout<<待输出的内容1<<待输出的内容2…;

例1.1使用cout进行简单的输出#include<iostream.h>voidmain(){ cout<<"您好"<<endl; cout<<"这是一个简单的C++程序"<<endl;}第1章C++与面向对象程序概述程序执行结果为:您好这是一个简单的C++程序使用cout及cin输入输出时必须包含的头文件输出换行1.4简单的C++程序1.4.2cin标准输入

cin>>保存数据的变量1>>保存数据的变量2…;

例1.2使用cin进行简单的输入#include<iostream.h>voidmain(){ inta,b; cin>>a>>b; cout<<a<<","<<b<<endl;}第1章C++与面向对象程序概述注意:运行时假设需要输入多个数据,数据间用空格分开

返回运行时,在键盘上输入1020,程序输出为:10,201.5VisualC++6.0编程环境简介1.5.1VisualC++6.0界面介绍VisualC++6.0集成开发环境的主界面由标题栏、菜单栏、工具栏、工作区〔Workspace〕、客户区、输出窗口和状态栏组成。第1章C++与面向对象程序概述1.5VisualC++6.0编程环境简介1.5.2编辑、编译和运行程序编写及运行程序的根本步骤如下:1.先建立工程〔Project〕2.向工程中添加源文件〔.cpp为扩展名〕3.编辑源文件〔输入源代码〕4.编译源文件〔查找并修改错误〕5.运行程序1.5.3程序调试如果程序运行结果与预计的结果不同,就需要对程序进行调试。调试时需要使用工具栏上的调试按钮,通过设置断点、单步执行、观察变量值等步骤,对程序的运行情况进行动态监测。第1章C++与面向对象程序概述

返回C++语言程序设计杨国兴张东玲彭涛第2章C++根底2.1常量与变量2.2指针与引用2.3动态内存分配2.4位运算符2.5名字空间2.1常量与变量2.1.1常量常量:在程序运行中,其值不能被改变的量称为常量。常量又分为直接常量和符号常量两种。1.直接常量:直接使用数值或文字表示的值〔1〕整型常量如:10、-20、0还可以八进制或十六进制表示:如034、0x23不带后缀的整型常量为int型,带后缀L或l可表示长整型常量,带后缀U或u表示无符号整型常量〔2〕实型常量如:2.18、-5.6、2.3E+2、-3.12E-2不带后缀的实型常量为double型,带后缀F或f可表示单精度实型常量第2章C++根底2.1常量与变量2.1.1常量〔续一〕〔3〕字符型常量以单引号括起来的单个字符:如‘a’、‘3’、‘*’转义字符:键盘不便于直接输入的字符,如回车符、制表符等,通常以“\〞开头表2.3转义字符\"双引号\'单引号\\字符‘\’\a响铃\b退格\n换行

\r回车

\t水平制表\v垂直制表\0003位八进制数所代表的字符,如‘\101’代表‘A’\xhh2位16进制所代表的字符,如‘\x41’代表‘A’第2章C++根底2.1常量与变量2.1.1常量〔续二〕〔4〕bool型常量bool常量只有两个:true(真)、false(假)在内存中占有一个字节的存储空间〔5〕字符串常量由一对双引号括起来的假设干字符,如“abc〞字符串常量的末尾自动参加结束标志‘\0’,因此字符串在内存中占有的字节数为字符个数+1假设字符串中包含特殊字符,如‘\’、回车、制表符等,也应以他们对应的转义字符形式表示第2章C++根底例2.1检测根本数据类型所占的字节数#include<iostream.h>voidmain(){ cout<<"int:"<<sizeof(int)<<endl; cout<<"short:"<<sizeof(short)<<endl; cout<<"long:"<<sizeof(long)<<endl; cout<<"float:"<<sizeof(float)<<endl; cout<<"double:"<<sizeof(double)<<endl; cout<<"longdouble:"<<sizeof(longdouble)<<endl; cout<<"char:"<<sizeof(char)<<endl; cout<<"bool:"<<sizeof(bool)<<endl;}

返回第2章C++根底2.1常量与变量2.1.1常量〔续三〕2.符号常量:直接使用符号表示的常量值,包括宏定义和const定义的符号常量。〔1〕宏定义语法形式:#define宏名字符串如:#definePI3.14程序编译前会自动用字符串取代程序中出现的宏名〔2〕const定义语法形式:const类型说明符常量名=常量值;如:constfloatpi=3.14;宏定义在预编译时,只进行简单的替换,不做语法检查宏定义没有数据类型,而const定义的符号常量是有数据类型的。第2章C++根底例2.2

使用符号常量#include<iostream.h>voidmain(){ #definePI3.14 constintA=10; cout<<PI*10*10<<'\n'; cout<<A+20<<'\n';}

返回第2章C++根底2.1常量与变量2.1.2变量1.变量的定义:程序运行中值可以被改变的量。变量必须先定义再使用。变量定义的一般形式语法形式:数据类型变量名1,变量名2,…,变量名n;如:inta,b,c;2.变量的初始化含义:定义变量的同时为其赋初值两种形式:用赋值号(“=〞)或用括号如:floata=3.14;或floata(3.14);第2章C++根底例2.3

从键盘输入n的值,计算从1到n的累加和。#include<iostream.h>voidmain(){ intn,sum=0; cin>>n; inti; for(i=1;i<=n;i++) sum+=i; cout<<sum<<'\n';}

返回第2章C++根底2.2指针与引用2.2.1指针1.地址与指针的概念〔1〕内存地址计算机的内存储器被划分成一个个的存储单元,这些存储单元按一定的规那么编号,这个编号就是存储单元的地址。每个存储单元的大小为一个字节,每个单元有一个唯一的地址。〔2〕变量的地址在程序中定义的所有变量,都要分配相应的存储单元,不同类型的数据所需要的存储空间的大小不同。系统分配给变量的内存空间的起始单元地址称为该变量的地址。如:inta;那么0x3000为变量a的地址0x30000x30010x30020x3003第2章C++根底2.2指针与引用2.2.1指针2.指针与指针变量〔1〕指针:一个变量的地址也称为该变量的指针。〔2〕指针变量:用于存储其它变量的指针(即地址)的变量。指针变量的定义:数据类型*指针变量名;如:int*p1;float*p2;char*p3;注意:指针变量所指向的变量类型不能改变指针变量必须指向具体内存地址才能引用,如:int*p;*p=10;〔3〕指针运算符(*)与取地址运算符(&)×第2章C++根底例2.4通过指针变量存取变量的值

#include<iostream.h>voidmain(){ inta,*p1; doubleb,*p2; charc,*p3; p1=&a; p2=&b; p3=&c; *p1=10; *p2=11.2; *p3='A'; cout<<a<<endl; cout<<b<<endl; cout<<c<<endl;}

程序运行结果为:1011.2A100x2000ap111.20x2004bp2A0x200Ccp3第2章C++根底例2.5输入a和b两个数,按从小到大的顺序输出#include<iostream.h>voidmain(){ inta,b; int*p1,*p2,*p; cout<<"请输入两个整数:"; cin>>a>>b; p1=&a; p2=&b; if(*p1>*p2) { p=p1; p1=p2; p2=p; } cout<<"min="<<*p1<<"max="<<*p2<<endl;}

程序运行结果为:请输入两个整数:3010min=10max=30&ap1&bp2p30a10b&bp1&ap2&ap30a10b第2章C++根底2.2指针与引用2.2.1指针3.指针作为函数的参数指针作为函数的参数,实际上传递的是变量的地址,进行的是地址传递。例2.6指针作为函数参数,被调函数中交换参数值#include<iostream.h>voidswap(int*x,int*y);voidmain(){inta,b;a=10;b=20;swap(&a,&b);cout<<a<<","<<b<<endl;}voidswap(int*x,int*y){inttemp;temp=*x;*x=*y;*y=temp;}第2章C++根底2.2指针与引用例2.6程序运行过程中变量值的变化分析yyb10ax20by&ax&b10temp20ax20by10temp&aax&bb10temp&a&btemp10a20&a&b2010(a)(b)(c)(d)程序运行结果为:20,10第2章C++根底2.2指针与引用2.2.2引用1.

引用的概念引用是一种特殊的变量,可以认为是一个变量的别名。

定义引用的一般格式:

类型说明符

&引用名=变量名;

如:inta=1;int&b=a;首先定义变量a,并初始化为1,然后定义引用b,并初始化为a,即b是a的别名,因此a和b是同一个单元。

注意:定义引用时一定要初始化,指明该引用变量是谁的别名。第2章C++根底例2.7引用的使用#include<iostream.h>voidmain(){inta=1;intc=10;int&b=a;cout<<a<<","<<b<<","<<c<<endl;b=c;cout<<a<<","<<b<<","<<c<<endl;b=20;cout<<a<<","<<b<<","<<c<<endl;}程序运行结果:1,1,1010,10,1020,20,10定义引用b,并将其作为a的别名将c的值赋给b,不是将b作为c的别名第2章C++根底2.2指针与引用2.2.2引用〔续一〕2.引用作为函数的参数例2.8写一个函数,用引用作为参数,交换函数中两个变量的值。#include<iostream.h>voidswap(intx,inty);voidmain(){inta,b;a=10;b=20;swap(a,b);cout<<a<<","<<b<<endl;}voidswap(int&x,int&y){inttemp;temp=x;x=y;y=temp;}程序运行结果为:20,10第2章C++根底2.2指针与引用2.2.2引用〔续二〕例2.8程序运行过程中参数值的变化图示10axby20axby10temp20axby10temp10axby10temp20202010注意:引用作参数时,函数的实参与形参在内存中共用存储单元,因此形参的变化会使实参同时变化。

返回第2章C++根底2.3动态内存分配在程序运行过程中根据需要动态分配存储空间,不需要时还可以将空间释放,通过new和delete运算符实现。1.动态分配一个数据的存储空间通过new运算符实现动态分配内存,格式如下:new类型名〔初值〕如:int*p1,*p2;p1=newint(10);p2=newint;运算符delete用来释放由运算符new动态分配的存储空间。使用格式如下:delete指针名;如:deletep1;第2章C++根底2.3动态内存分配2.动态分配多个连续的数据存储空间通过new运算符动态分配数组,格式如下:new类型名[整型表达式]如:int*p1;p1=newint[10];用delete删除动态数组时,要在指针前加“[]〞。格式如下:delete[]指针名;如:delete[]p1;第2章C++根底例2.9动态内存分配的使用#include<iostream.h>voidmain(){ int*p1,*p2; p1=newint(10); p2=newint[10]; inti; for(i=0;i<10;i++) *(p2+i)=i; cout<<*p1<<endl; for(i=0;i<10;i++) cout<<*(p2+i)<<""; cout<<endl; for(i=0;i<10;i++) cout<<p2[i]<<“〞;//p2[i]与*(p2+i)所访问的数据相同 cout<<endl;deletep1; delete[]p2;}程序运行结果为:1001234567890123456789

p212345678910

返回第2章C++根底2.4位运算符2.4.1位运算符C++使用位运算符可以对数据按二进制位进行操作。1.按位与〔&〕:将两个操作数对应的每一位分别进行逻辑与如:9&79:000010017:000001119&7:000000019&7结果为12.按位或〔|〕:将两个操作数对应的每一位分别进行逻辑或3.按位异或〔^〕:将两个操作数对应的每一位分别进行异或第2章C++根底2.4位运算符2.4.1位运算符〔续〕4.按位取反〔~〕:单目运算符,对二进制的每一位取反5.左移位〔<<〕:使运算符左侧的操作数的各位左移指定位数,低位补0,高位溢出局部舍弃。如7<<2结果为28。6.右移位〔>>〕:使运算符左侧操作数的各位右移指定位数,溢出的低位舍弃,对无符号数和有符号中的正数,高位补0,对于有符号数中的负数,有些系统补0〔称为逻辑右移〕,有些系统补1〔称为算术右移〕。如7>>2的结果是1。000001117000111007<<2第2章C++根底2.4位运算符2.4.2位运算符应用举例

例2.10输入变量a,b的值,并将变量a的低4位置为0,将变量b的低4位置为1。#include<iostream.h>voidmain(){ inta,b; cin>>a; cin>>b; a=a&(~0xf); b=b|0xf; cout<<a<<endl; cout<<b<<endl;}0xf为十六进制数,它的后四位为1,其他位均为0。取反后后四位为0,其他位均为1。假设输入25和23,程序执行结果为:1631

返回第2章C++根底2.5名字空间2.5.1名字空间的定义与使用

1.名字空间的定义

namespace名字空间名{…………}

例:

namespaceNameSpace1{inta;intf1(){……}floatf2(){……}}〔1〕名字空间只能在全局范围那定义,但名字空间是可以嵌套的。〔2〕一个名字空间可以用另一个名字作为它的别名。例如使用ns1作为上述名字空间NameSpace1的别名,可以用下面的语法:namespacens1=NameSpace1;第2章C++根底2.5名字空间2.5.1名字空间的定义与使用2.名字空间的使用〔1〕使用域运算符格式如下:名字空间名::标识符例如下面一行程序,可以访问名字空间NameSpace1中的变量a和函数f1〔〕。NameSpace1::a=NameSpace1::f1();第2章C++根底例2.11名字空间的定义与使用#include<iostream.h>namespacens1{intfun(intx,inty);}namespacens2{intfun(intx,inty);namespacens3{ intfun(intx,inty);}}intns1::fun(intx,inty){returnx+y;}intns2::fun(intx,inty){returnx*y;}intns2::ns3::fun(intx,inty){returnx-y;}voidmain(){cout<<ns1::fun(3,4)<<endl;cout<<ns2::fun(3,4)<<endl;cout<<ns2::ns3::fun(3,4)<<endl;}程序运行结果:712-1第2章C++根底2.5名字空间2.5.1名字空间的定义与使用2.名字空间的使用〔2〕使用using指令格式如下:using名字空间名;using名字空间名::标识符;第一种格式表示在当前范围内,可以直接使用指定名字空间中定义的变量和函数等,而不需要加名字空间的限定。第二种格式表示在当前范围内,可以直接使用指定名字空间中指定的变量或函数,而不需要加名字空间的限定。第2章C++根底例2.12

使用using指令#include<iostream.h>namespacens1{ intfun1(intx,inty); intfun2(intx,inty); intfun3(intx,inty); intfun1(intx,inty) { returnx+y; } intfun2(intx,inty) { returnx-y; } intfun3(intx,inty) { returnx*y; }}usingnamespacens1;voidmain(){ cout<<fun1(3,4)<<endl; cout<<fun2(3,4)<<endl; cout<<fun3(3,4)<<endl;}程序运行结果:7-112第2章C++根底2.5名字空间2.5.2C++标准库C++标准库就被所有的C++编译器支持,所有标准C++的库都包含在一个单一的名字空间std中。为了使用C++的标准库,可以使用以下指令:usingnamespacestd;例:使用标准库的程序#include<iostream>usingnamespacestd;voidmain(){cout<<“本例使用标准库〞<<endl;}注意:由于iostream和iostream.h都定义了cout,因此不能同时包含这两个文件,否那么将产生二义性。第2章C++根底C++语言程序设计杨国兴张东玲彭涛第3章函数3.1函数的递归调用3.2内联函数3.3函数重载3.4带默认参数值的函数3.5变量的存储类别3.6程序实例3.1函数的递归调用一个函数在它的函数体内,直接或间接地调用它自身,称为递归调用。这种函数称为递归函数。

直接或间接调用函数自身的情况如图:

第3章函数f函数调用f函数f1函数调用f2函数f2函数调用f1函数直接调用间接调用这两种递归调用都是无中止地调用自身,显然是不正确的。为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。例3.1用递归的方法求n!分析:计算n!的公式为:1n=1或0y=n*(n-1)!n>1

可以将求n!转化为求(n-1)!,再继续转化为求(n-2)!,到1时应停止递归#include<iostream>usingnamespacestd;longpower(intn);voidmain(){

intn;

longy;

cout<<"inputaintegernumber:";

cin>>n;

y=power(n);

cout<<n<<"!="

<<y<<endl;}第3章函数longpower(intn){

longf;

if(n>1)

f=n*power(n-1);

else

f=1;

returnf;}例3.1的递归过程分析第3章函数例3.2Hanoi塔问题有三根针A、B、C,A针上有n个盘子,盘子大小不等,大的在下,小的在上,如下图。要求将这n个盘子从A针移到C针,在移动过程中可以借助B针,每次只能移动一个盘子,并且在移动过程中三根针上的盘子都保持大盘在下,小盘在上。分析:将n个盘子从A针移到C针可以分解为以下三个步骤:〔1〕将A针上的n-1个盘子借助C针移到B针上;〔2〕将A针上剩下的一个盘子移到C针上;〔3〕将B针上的n-1个盘子借助A针移到C针上。第3章函数ABCn-1个盘子的Hanoi问题例3.2Hanoi塔问题源程序#include<iostream>usingnamespacestd;voidMove(charx,

chary);voidHanoi(intn,charone,chartwo,charthree);voidmain(){

intn;

cout<<"请输入盘子数:";

cin>>n;

cout<<n<<"个盘子的移动过程为:"<<endl;

Hanoi(n,'A','B','C');}//函数Move()将一个盘子从x针移到y针voidMove(charx,

chary){

cout<<x<<"-->"<<y<<endl;}第3章函数例3.2Hanoi塔问题源程序〔续〕//函数Hanoi()将n-1个盘子从one针借助two针移到three针voidHanoi(intn,charone,chartwo,charthree){

if(n==1)

Move(one,three);

else

{

Hanoi(n-1,one,three,two);

Move(one,three);

Hanoi(n-1,two,one,three);

}}第3章函数程序运行结果:A

CA

BC

BA

CB

AB

CA

C

返回运行演示3.2内联函数内联函数与一般函数的区别在于它不是在调用时发生控制转移,而是在编译时将被调函数体嵌入到每一个函数调用处,节省了参数传递、控制转移等开销。对于一些规模较小、频繁调用的函数可声明为内联函数,能提高程序运行效率。内联函数的定义:inline类型说明符函数名〔参数及类型表〕{函数体}注意:只有简单的函数才能成为内联函数,如函数体中不能有循环语句和switch语句等。内联函数的定义必须出现在内联函数第一次被调用之前。第3章函数例3.3使用内联函数#include<iostream>usingnamespacestd;inlineintAdd(inta,intb){ intx; x=a+b; returnx;}第3章函数程序运行结果:10+20=3010+50=6050+50=100

返回voidmain(){ inta,b,c; a=10; b=20; c=Add(a,b); cout<<a<<"+"<<b<<"="<<c<<endl; c=Add(a,50); cout<<a<<"+50"<<"="<<c<<endl; c=Add(50,50); cout<<"50+50"<<"="<<c<<endl;}3.3函数重载

在C++中可以定义多个相同名字的函数,只要它们形参的个数或类型不完全一致即可,编译程序根据实参与形参的类型及个数自动确定调用哪一个同名函数,这就是函数重载,这些同名函数称为重载函数。

例3.4

定义两个函数,分别求两个整数及两个实数的最大值。分析:在C语言中,要定义题中的函数,只能使用两个不同名函数实现,即定义intmax1(intx,inty)doublemax2(doublex,doubley)

在C++中,可通过定义两个重载函数实现,二者同名,如下:

intmax(intx,inty)doublemax(doublex,doubley)第3章函数例3.5源程序#include<iostream>usingnamespacestd;intmax(intx,inty);doublemax(doublex,doubley);voidmain(){ inta=10,b=20,c; doublex=200.3,y=400.6,z; c=max(a,b); z=max(x,y); cout<<c<<""<<z<<endl;}第3章函数程序运行结果:intfunctionfloatfunction20,400.6

返回intmax(intx,inty){ cout<<"intfunction"<<endl; if(x>y)returnx; else returny;}doublemax(doublex,doubley){ cout<<"floatfunction"<<endl; if(x>y) returnx; else returny;}3.4带默认参数值的函数3.4.1带默认参数值的函数在函数的声明或定义中可以预先给出默认的形参值,函数调用时,按从左到右的次序将实参和形参结合,如给出对应的实参,那么采用实参值,否那么采用预先给出的默认形参值。例3.6使用带默认参数值的函数求x的n次方〔n是正整数〕。

第3章函数#include<iostream>usingnamespacestd;doublepower(doublex=10.0,intn=2);voidmain(){ cout<<power(3,5)<<endl; cout<<power(3)<<endl; cout<<power()<<endl;}

doublepower(doublex,intn){ inti; doubles=1.0; for(i=1;i<=n;i++) s*=x; returns;}

3.4带默认参数值的函数3.4.1带默认参数值的函数〔续〕注意:默认形参值必须由右向左的顺序定义。如果某个参数有默认值,那么其右面的参数必须都有默认值;如果某个参数没有默认值,那么其左面的参数都不能有默认值。例如:intmax(inta,intb=10,intc=20);//正确intmax(inta,intb=10,intc);//错误intmax(inta=5,intb,intc=30);//错误在后两种情况下,调用语句x=max(20,30);会出错!注意:在使用带默认参数值的函数时,只能在函数定义或函数声明中的一个位置给出默认值,不能在两个位置同时给出。还要保证在函数调用之前给出默认值。第3章函数3.4带默认参数值的函数3.4.2带默认参数值函数产生的二义性

例3.7程序第3章函数#include<iostream>usingnamespacestd;intadd(intx=5,inty=6);floatadd(intx=5,floaty=10.0);voidmain(){ inta; floatb; a=add(10,20); b=add(10);

cout<<"a="<<a<<endl; cout<<"b="<<b<<endl;}

intadd(intx,inty){returnx+y;}floatadd(intx,floaty){returnx+y;}

b=add(10)语句产生二义性,可以认为该语句是调用第一个函数,也可以是第二个,因此编译器不能确定调用的是哪一个函数。

返回3.5变量的存储类别3.5.1内部变量与外部变量1.内部变量在一个函数内部定义的变量是内部变量〔也称为局部变量〕,它只在该函数范围内有效。例如:

第3章函数voidf1(inta){intb,c;

……} voidmain(){intm,n;

……}a,b,c的有效范围m,n的有效范围inti,a;……for(i=0;i<10;i++){intb;……}

b的有效范围注意:在不同的作用范围内允许声明同名的变量3.5变量的存储类别3.5.1内部变量与外部变量〔续〕2.外部变量在函数外部定义的变量是外部变量〔也称为全局变量〕,它不属于任何一个函数。它的作用范围是:从外部变量的定义位置开始,到本文件的结尾。例如:

第3章函数inta,b;

voidf1(){

……} intx,y;voidmain(){……}x,y的有效范围a,b的有效范围例3.8使用全局变量和局部变量#include<iostream>usingnamespacestd;inti=1;

//全局变量,文件作用域

voidmain(){

cout<<"全局变量i="<<i<<endl;

//输出1

inti=5;

//函数局部变量,块作用域

{

inti;//块局部变量,块作用域

i=7;

cout<<"块局部变量i="<<i<<endl;

//输出7

cout<<"全局变量i="<<::i<<endl;//输出1,::使用全局变量

}

cout<<"函数局部变量i="<<i<<endl;

//输出5

cout<<"全局变量i="<<::i<<endl;//输出1,::使用全局变量

}第3章函数程序运行结果:全局变量i=1块局部变量i=7全局变量i=1函数局部变量i=5全局变量i=1

3.5变量的存储类别3.5.2变量的存储类别变量在内存中的存储方式可以分为两大类,即静态存储方式与动态存储方式。静态存储方式是指在程序运行期间,分配固定的存储空间。全局变量和静态局部变量是静态存储方式。动态存储方式是在程序执行过程中,根据需要动态地分配存储空间。局部变量是动态存储方式。1.静态变量定义形式:static数据类型变量名特点:程序运行过程中变量始终存在,每次调用函数结束的值都被保存下来。仅初始化一次,每次调用它所在的函数时,不再重新初始化。假设不指定初值,自动指定初值为0。第3章函数例8.9输出1~4的阶乘#include<iostream>usingnamespacestd;intfact(intn); voidmain(){ inti; for(i=1;i<=4;i++) cout<<i<<"!="<<fact(i)<<endl;}intfact(intn){ staticintf=1; //仅在第一次调用函数时执行一次 f*=n; returnf;}第3章函数程序运行结果:1!=12!=23!=64!=24

3.5变量的存储类别3.5.2变量的存储类别〔续〕2.自动变量定义形式:auto数据类型变量名特点:定义变量时,假设不指定static或auto,那么默认为自动变量。自动变量是动态存储方式。每次调用它所在的函数时,都要重新分配存储空间,并初始化。函数调用结束,存储空间就释放。假设不初始化,那么初值是不确定的。第3章函数例3.10静态变量与动态变量的使用#include<iostream>usingnamespacestd;voidother(void);inti=1;//i为全局变量,具有静态生存期。

voidmain(void){ staticinta;//a为静态局部变量,具有全局寿命,局部可见。

intb=-10;//b,c为动态局部变量,具有局部生存期。

intc=0; cout<<"---MAIN---\n"; cout<<"i:"<<i<<"a:"<<a<<"b:"<<b<<"c:"<<c<<endl; c=c+8; other(); cout<<"---MAIN---\n"; cout<<"i:"<<i<<"a:"<<a<<"b:"<<b<<"c:"<<c<<endl; i=i+10; other();}第3章函数例3.10静态变量与动态变量的使用(续)voidother(void){

//a,b为静态局部变量,具有全局寿命,局部可见,

//只第一次进入函数时被初始化。

staticinta=2; staticintb; intc=10;//C为动态局部变量,每次进入函数时都初始化。

a=a+2; i=i+32; c=c+5; cout<<"---OTHER---\n"; cout<<"i:"<<i<<"a:"<<a<<"b:"<<b<<"c:"<<c<<endl; b=a;}第3章函数程序运行结果:---MAIN---i:1a:0b:-10c:0---OTHER---i:33a:4b:0c:15---MAIN---i:33a:0b:-10c:8---OTHER---i:75a:6b:4c:15例3.11输出摄氏温度与华氏温度对照表分析:编写一个函数求出指定摄氏温度对应的华氏温度值,在主函数中通过循环求出摄氏温度从0~99度对应的华氏温度值,并输出。转换公式为:

F=9/5*C+32其中F表示华氏温度,C为摄氏温度。程序如下:

#include<iostream>#include<iomanip>usingnamespacestd;intConvert(intc){ intf; f=(int)(9.0/5*c+32); returnf;}第3章函数例3.11〔续一〕#voidmain(){ cout<<"|0123456789"<<endl; cout<<"---|----------------------------------------------------------"<<endl; for(inti=0;i<10;i++) {

cout<<setw(2)<<i*10<<"|"; for(intj=0;j<10;j++) { cout<<setw(3)<<Convert(i*10+j)<<""; } cout<<endl; }}第3章函数例3.11〔续二〕程序运行结果:第3章函数例3.12用递归的方法计算从n个人中选取k个人的组合数分析:从n个人中选取k个人的组合数=从n-1个人中选取k个人的组合数+从n-1个人中选取k-1个人的组合数当n与k相等,或k等于0时,组合数为1,即有以下公式〔comm表示组合数〕:1n==k或k==0comm〔n,k〕=comm(n-1,k)+comm(n-1,k-1)n!=k且k>0第3章函数例3.12〔续〕#include<iostream>usingnamespacestd;intcomm(intn,intk);voidmain(void){ intn,k; cout<<"请输入n和k的值:"; cin>>n>>k; cout<<comm(n,k)<<endl;}intcomm(intn,intk){ if(k>n) return0; elseif((n==k)||(k==0)) return1; else returncomm(n-1,k)+comm(n-1,k-1);}第3章函数

返回程序运行结果:请输入n和k的值:103120C++语言程序设计杨国兴张东玲彭涛第4章类与对象4.1类与对象4.2构造函数与析构函数4.3类的组合4.4友元4.5静态成员4.6对象数组与对象指针4.7this指针4.1类与对象4.1.1类与对象的概念对象(object):是现实世界中的客观事物。类(class):是把具有相同属性的事物划分为一类,从而得出的抽象概念。面向对象程序设计中的类,是具有相同属性和效劳的一组对象的集合,它为属于该类的全部对象提供了抽象的描述。对象是类的实例,类是同种对象的抽象。第4章类与对象如:确定大小和颜色的矩形都是一个个具体的对象,而将所有矩形的共同特点抽象出来,就是一个矩形类。这些共有的属性包括颜色(color),左上角坐标(left,top),长(length)和宽(width)等;对这些属性的处理包括改变矩形的颜色(SetColor)和大小(SetSize),移动矩形到新的位置(Move),绘出矩形(Draw)等。将矩形的这些属性和方法作为一个整体,封装在一起形成一个矩形类。4.1类与对象4.1.2类的声明

class类名{

private:私有数据成员和成员函数;protected:保护数据成员和成员函数;public:公有数据成员和成员函数;

};第4章类与对象例4.1定义一个长方形类CRect,其数据成员包括颜色,左上角坐标,长和宽,其函数成员包括改变矩形的颜色(SetColor)和大小〔SetSize〕,移动矩形到新的位置〔Move〕,绘出矩形〔Draw〕。classCRect{private: charcolor[10]; intleft; inttop; intlength; intwidth;public: voidSetColor(char*c); voidSetSize(intl,intw); voidMove(intt,intl); voidDraw();};第4章类与对象例4.1〔续一〕voidCRect::SetColor(char*c){ strcpy(color,c);}voidCRect::SetSize(intl,intw){ length=l; width=w;}voidCRect::Move(intt,intl){ top=t; left=l;}voidCRect::Draw(){ cout<<"矩形左上角坐标为("<<left<<","<<top<<")"<<endl; cout<<"矩形长和宽分别为"<<length<<","<<width<<endl; cout<<"矩形的颜色是"<<color<<endl;}第4章类与对象域运算符〔::〕用于指出该函数是哪一个类的成员函数,用法:类名::函数名〔参数表〕例4.1〔续二〕voidmain(){ CRectr; r.SetColor("Red"); r.Move(10,20); r.SetSize(100,200); r.Draw(); r.Move(50,50); r.SetColor("Blue"); r.Draw();}第4章类与对象定义CRect类的对象,定义对象的格式:类名对象名1,对象名2,……访问对象的公有成员,格式为:对象名.公有成员函数名〔参数表〕对象名.公有数据成员名程序运行结果为:矩形左上角坐标为〔20,10〕矩形长和宽分别为100,200矩形的颜色是Red矩形左上角坐标为〔50,50〕矩形长和宽分别为100,200矩形的颜色是Blue4.1类与对象4.1.3成员的访问控制private:私有访问权限,只允许类中的成员函数访问,其他函数不能访问。protected:保护访问权限,在第7章中介绍。public:公有访问权限,在任何函数中都可以访问。

例:假设主函数中有以下语句,是否正确?CRectr;strcpy(r.color,“red〞);r.top=10;r.left=20;第4章类与对象在主函数中不能访问类的私有成员4.1类与对象4.1.3成员的访问控制〔续〕假设不指定类中的成员的访问权限,那么默认为私有成员。类也可以由struct关键字声明,strust与class的区别是:如果不指定访问权限,前者缺省的访问权限是公有的,而后者是私有的。用struct声明前面的矩形类:structCRect{ voidSetColor(char*c); voidSetSize(intl,intw); voidMove(intt,intl); voidDraw();private: charcolor[10]; intleft; inttop; intlength; intwidth;};第4章类与对象4.1类与对象4.1.4类的成员函数1.类成员函数的定义方式在类外部定义:如前面定义的长方形类的成员函数一般格式为:函数类型类名::成员函数名〔参数说明〕{函数体}在类中定义:如classCRect{ ……public: voidsetcolor(char*c){strcpy(color,c);}……};第4章类与对象4.1类与对象4.1.4类的成员函数〔续一〕2.内联成员函数将成员函数的定义直接写在类中即成为内联成员函数在类外定义时用inline指出:如:inlinevoidCRect::SetColor(char*c){ strcpy(color,c);}第4章类与对象4.1类与对象4.1.4类的成员函数〔续二〕3.带默认参数值的成员函数注意:默认参数只能在声明或定义中的一处给出,即如在类中的函数声明已经给出默认参数值: voidSetSize(intl=100,intw=100);那么在函数定义时就不能再给出默认值。同样如果在定义时给出了默认值:voidCRect::SetSize(intl=100,intw=100){ length=l; width=w;}在声明处就不能再给默认值了。第4章类与对象

返回4.2构造函数与析构函数构造函数:对对象进行初始化。析构函数:在对象销毁时进行内存释放等清理工作。4.2.1构造函数1.构造函数的特点(1)构造函数的函数名与类名相同。(2)不能定义构造函数的类型〔即不能指明构造函数返回值的类型〕。(3)构造函数应声明为公有函数。(4)构造函数不能在程序中调用,在对象创立时,构造函数被系统自动调用。2.构造函数的作用构造函数的作用就是在对象被创立时利用特定的值构造对象,将对象初始化为一个特定的状态,使此对象具有区别于其它对象的特征。第4章类与对象例

为CRect类添加构造函数classCRect{private: charcolor[10];……public: CRect(); CRect(char*c,intt,intleft,intlen,intwid); voidSetColor(char*c);……};

CRect::CRect(){ strcpy(color,"Black"); top=0; left=0; length=0; width=0;}二者是重载函数,在定义对象时,如果不给出参数,就自动调用第一个构造函数,如果给定5个参数就自动调用第二个构造函数。

第4章类与对象例为CRect类添加构造函数〔续〕CRect::CRect(char*c,intt,intlef,intlen,intwid){ strcpy(color,c); top=t; left=lef; length=len; width=wid;}voidmain(){ CRectr1;//自动调用第一个构造函数CRectr2(“red〞,10,10,100,100);//自动调用第二个构造函数 CRectr3("green",200,200,50,50);//自动调用第二个构造函数 r1.Draw(); r2.Draw(); r3.Draw();}第4章类与对象例4.2构造函数的初始化表#include<iostream>usingnamespacestd;classA{private: constdoublePI;intb; int&c;public: A(intx):PI(3.14),c(b) { b=x; } voidOutput() { cout<<PI<<","<<b<<","<<c<<endl; }};第4章类与对象voidmain(){ Ax(10); x.Output();}程序运行结果:3.14,10,104.2构造函数与析构函数4.2.2析构函数1.析构函数的特点(1)析构函数名字为符号“~〞加类名。(2)析构函数没有参数,不能指定返回值类型。(3)一个类中只能定义一个析构函数,所以析构函数不能重载。(4)当一个对象作用域结束时,系统自动调用析构函数。如CRect类的析构函数声明为:~CRect();定义为:CRect::~CRect(){……}2.析构函数的作用

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论