您好,欢迎来到易榕旅网。
搜索
您的当前位置:首页C++面向对象程序设计_自学指导书

C++面向对象程序设计_自学指导书

来源:易榕旅网
《C++面向对象程序设计》 函授自学指导书

《C++面向对象程序设计》

自学指导书

浙江师范大学 信息科学与工程学院

朱建新 编

2005年4月30日

1

《C++面向对象程序设计》 函授自学指导书

目 录

第一章 C++语言概述 ........................................................................................... 4

【学习要点】.................................................................................................. 4 【例题分析】.................................................................................................. 4 【思考题】...................................................................................................... 5 第二章 基本数据类型 运算符及表达式............................................................. 6

【学习要点】.................................................................................................. 6 【例题分析】.................................................................................................. 6 【思考题】...................................................................................................... 8 第三章 控制结构................................................................................................... 8

【学习要点】.................................................................................................. 8 【例题分析】.................................................................................................. 9 【思考题】.................................................................................................... 17 第四章 数组......................................................................................................... 20

【学习要点】................................................................................................ 20 【例题分析】................................................................................................ 21 【思考题】.................................................................................................... 24 第五章 函数与编译预处理................................................................................. 33

【学习要点】................................................................................................ 33 【例题分析】................................................................................................ 33 【思考题】.................................................................................................... 40 第六章 指针......................................................................................................... 49

【学习要点】................................................................................................ 49 【例题分析】................................................................................................ 50 【思考题】.................................................................................................... 58 第七章 结构体与共用体..................................................................................... 60

【学习要点】................................................................................................ 60 【例题分析】................................................................................................ 60 【思考题】.................................................................................................... 67 第八章 类与对象................................................................................................. 70

【学习要点】................................................................................................ 70 【例题分析】................................................................................................ 71 【思考题】.................................................................................................... 77 第九章 继承与派生类......................................................................................... 80

【学习要点】................................................................................................ 80 【例题分析】................................................................................................ 80 【思考题】.................................................................................................... 84 第十章 运算符重载与虚函数............................................................................. 89

【学习要点】................................................................................................ 89 【例题分析】................................................................................................ 89 【思考题】.................................................................................................... 99 第十一章 文件与流类库................................................................................... 100

【学习要点】.............................................................................................. 100

2

《C++面向对象程序设计》 函授自学指导书

【例题分析】.............................................................................................. 100 【思考题】.................................................................................................. 105

3

《C++面向对象程序设计》 函授自学指导书

第一章 C++语言概述

本章主要介绍C+十的起源、发展历史及其特点;C+十程序的基本结构;Visual C++6.0集成开发环境及上机操作过程。

【学习要点】

1. 了解C+十语言的特点。

2. 理解C+十语言源程序的结构、书写格式和main()函数的作用。

3. 熟悉 Visual C++6.0集成开发环境。熟练掌握利用 Visual C++6.0集成开发环境开发、调试C+十控制台程序的步骤和基本操作。

【例题分析】

一、选择题

例1-1 以下叙述中正确的是_。 A. C+十程序由main()函数组成 B. C+十程序由函数组成

C. C+十程序的执行从第一个函数开始

D. 在C+十程序中,注释只能位于一条语句之后 解:对于C+十程序应明确:

(l)程序由函数组成。一个可运行的C+十源程序可由一个且仅能由一个 main()函数加上其他的函数组成,其他函数可有可无。

(2)不管main()函数出现在什么位置,程序总是从main()函数开始执行。

(3)注释的两种方法:一是用/*和*/把注释信息括起来;二是用//,它表示//之后到本行结束为注释内容。可以在程序任何位置进行注释。 正确答案:B。 二、填空题

例1-2 在下列程序的每行之后加上注释。 #include \"iostream.h\" void main() {

cout<<\"Hello!\\n\";

cout<<\"Welcome to C++!\\n\"; }

解:注释如下:

#include \"iostream.h\" //指示编译器在此处将文件iostream.h上中的代码嵌入本程序。

void main() //主函数,void表示 main()函数没有返回值。 {

cout<<\"Hello!\n\";//输出字符串“Hello!”到显示器上。

4

《C++面向对象程序设计》 函授自学指导书

cout<<“Welcome to C++!\\n\";//输出字符串“Welcome to C++!\\n”。 }

例1-3 C+十中函数的函数体由符号_开始,用符号_结束。

解:C+十中函数的函数体由符号“{”开始,用符号“}”结束。 三、 编程题

例1-4 编写一个程序,运行时提示输入一个数字,再把这个数字显示出来。 解: 程序如下:

#include \"iostream.h\" void main( ) {

int i;

cout<<\"请输入一个数字:\"; cin>>i;

cout<<\"你输入的数字是\"<【思考题】

一、选择题

1. C+十语言规定:在一个源程序中,main()函数的位置_。 A. 必须在最开始

B. 必须在系统调用的库函数的后面 C. 可以任意 D. 必须在最后

2. 以下正确的叙述是_。

A. C+十程序的每行中只能写一个语句 B. C+十语言本身无输入、输出语句

C. 在对一个C+十源程序进行编译的过程中,可发现注释中的拼写错误 D. 在C+十程序中,main()函数必须位于程序的最前面 3. 以下符号中能作为用户标识符的是_。 A. 123 B. void C. struct D .switch 4. C+十语言程序的基本单位是_。 A. 程序行B. 语句C. 函数D. 字符 二、填空题

5. 一个可执行的C+十程序至少必须有一个_函数。 6. C+十源程序中注释的作用是_。

7. 一个C+十语句以_结束。_是C+十语句的组成部分。 8. 在C+十语言中输入、输出操作是通过_来实现的。 9. 在下列程序的每行之后力,上注释。 #include<iostream.h> void main() {

int nl, n2, sum;

cont<<\"Emter two numbers n1,n2:\"; cin>>n1>>n2; sum=n1+n2;

cout<<\"n1+n1=\"<<sum<<endl;

5

《C++面向对象程序设计》 函授自学指导书

三、编程题

10. 参照例题分析,编写一个C+十程序并上机运行,能输出以下信息:

************************************** Hello,C++!

**************************************

11. 编写一个C+十程序,输入任意三个数a,b,c,能输出其中的最大值。

第二章 基本数据类型 运算符及表达式

本章是C+十语言中需要熟记的内容最多的一章,对于数据类型、运算符、表达式等内容既要熟记,更要灵活运用;特别要注意与自然语言明显不同的逗号运算、自增自减等运算的特点。

【学习要点】

1. 掌握常量与变量、整型数与实型数的概念。

2. 掌握字符型数据与字符串型数据的概念以及二者的区别。 3. 掌握各种类型的变量说明及其初始化。

4. 掌握算术运算、逻辑运算、关系运算、赋值运算、逗号运算等概念。 5. 掌握运算符的优先级、左结合和右结合规则以及目数的概念。 6. 掌握表达式求值时类型的自动转换和强制类型转换。 7. 掌握表达式的组成、表达式的优化。 8. 掌握位运算和位运算符。

【例题分析】

一、选择题

例 2-1 下列不合法的变量名为_

A. student B. -student C._student D. student()

解:根据变量命名要求,首字母以英文字母或下划线开头。 正确答案:B。

例 2-2 下列不合法的变量名为

A.t%udent B.astudent C.s_tudent D.studen()

解:根据变量命名要求,变量名组成只能由大小写字母、数字、下划线组成。 正确答案:A。

例2-3 下列不合法的变量名为_

A.lint B.int1 c.int D._lint

解:根据变量命名要求,系统关键字不能作为变量名。 正确答案:C。

例 2-4 当 a=6,b=5时,逻辑表达式 a<=7&&a+b>8的值为__ A.true B.false C. 非0整型数 D. 0 解:根据题意和该逻辑表达式的运算结果。

6

《C++面向对象程序设计》 函授自学指导书

正确答案:C。

例 2-5 设 X,y,Z为整型数,下列各式中,运算结果与 X=y=24的表达式相同的是_。

A.x=(y=z=8,4×6) B.x= y=(z=8,4×6) C.X= y= z=8,4×6 D.x=(y= z= 8),4×6

解:C++语言的赋值运算有别于其他高级语言,逗号运算又是其他高级语言所没有的。

1. 在赋值表达式中,可以有多个赋值运算符;计算顺序自右向左,运算优先级低,仅高于远号运算符。

2. 逗号既是分隔符,又是运算符,可以用一个逗号运算符或多个逗号运算得将多个表达式连接成逗号表达式,计算顺序自左向右,并将最后一个表达式的值作为整个逗号表达式的值,运算优先级最低;例:a=(2×2, 4+6,20/4,6);结果a=6。

正确答案:B。

例2-6 设i=6,k=0下列各式中,运算结果为k=7 的表达式是_。

A. k=i+++k B. k=k+i++ C. k=++i+k D.k=k+(十十i) 解:自增十十、自减――运算符是C+十语言特有的。

1.运算符在变量的前面或后面,其运算结果是不同的。若十十或--在变量前;则先将变量的值加1(或减 1后,再将变量的值参加运算;反之则先将变量的值参加运算;再将变量的值加1(或减1)。

2.自增、自减运算符优先级高于算术运算符,A式i+++k,先计算i++,

再力。k,D式 k= k+(++i),若去掉括号,则改变了运算顺序;变为 k+十后, 再十l。

正确答案;C和D。 二、填空题

例 2-7 表达式'A'+'B'+20的值为_

解:不同类型的数据混合运算时,系统可以自动进行类型转换,将表示范围小的数据类型转换成另一操作数的相同类型后再参与运算,则转换为65+66+20=151。

例2-8 如果定义int e=8;double f=6.4,g=8.9;则表达式f+int(e/3*int (f+g)/2)%4的值为_。

解:不同类型的数据混合运算时,可以使用强制类型转换符,强制将一种数据类型转换成另一种数据类型后再参与运算,对于表达式,先求表达式的值,然后再转换值的类型,本例的运算结果为 9.4 。若将式中 e/3改为 e/3.0

则运算结果为6.4,因为e/3的值是整型数,而e/3.0的值是实型数,改变了括号内的运算结果,致使整个表达式的值发生变化。

例2-9 若int i= 65535,j =0x000x,k:k=i&j; ,则k值为_,i值为_。 解:将 10进制数65535和 16进制数000aH在计算机内的二进制原型数值按位与运算,结果为 k= 10,i为 65535。

三、编程题

例 2-10 编写一个将华氏温度转换为摄氏温度的程序。转换公式为 C=(5.0/9)(F—32),要求输出华氏温度和摄氏温度的对应值。

解:程序如下: #include void main() {

double C,F;

7

《C++面向对象程序设计》 函授自学指导书

cout<<\"输入华氏温度值:\"; cin>>F;

C=(5.0/9)*(F-32);

cout<<\"华氏温度为:\"<【思考题】

一、选择题

1. 以下可作为正确变量名的是_。

A .class B. class1 C. 1class D. cl\\ass 2 以下可作为正确变量名的是。

A .case B.-cd C. 33 D. 33s

3.若a=15,b=3 时,逻辑表达式a<=7&&a+b>8 的值为 A.ture B.false C. 非0整型数 D.0

4. 若a和b为整型变量,语句b= (a=1+2 a×3),a+5运行后,a

和b的结果为

A .9,8 B. 3,8 C. 3,9 D. 9,14 5. 以下不正确的叙述是_。

A.在C+十程序中,PI和pi是不同的变量 B.在C+十程序中,逗号运算符的优先级最低

C.当从键盘输入数据时,对于整型变量只能输入整型数值,对于实型变量只能输入实型数值

D. 若 s、t为int数,设 t=S>>2后,s的值不变

6.若int a;char b;float c; double d;则表达式a*b-c+d值的数据类型为_。 A. int B. float C. double D. char

7. 已知字母 A的ASCII码为十进制数 65,D为字符型变量,则D='A'+'9'-'4'

的值_ 。

8. 若a为16进制数,若想通过a&b运算使a的二进制数的高4位清零,低4位不变;则 b的 16进制数是_。

9. 编制程序,输入相应字母的 ASCII码值,输出该字母。 10. 用C+十描述下面命题: (1)a小于b或大于c

(2)a和b中至少有一个大于c。 (3)a和b中只有一个大于c。 (4)a和b中两个都大于c。

第三章 控制结构 【学习要点】

1.掌握顺序结构的编程方法,这是程序设计的基础。

8

《C++面向对象程序设计》 函授自学指导书

2.学会cin、cout实现输入/输出数据。 3.学会应用字符输入/输出函数。 4.掌握 printf函数和 scanf函数。 5.掌握条件语句的形式和使用. 6.掌握条件语句的嵌套。 7.掌握条件运算符的使用。

8.掌握switch语句的形式和使用。

9.掌握 for,while,do—while三种循环语句。 10.掌握循环的嵌套。

11.掌握break,continue,goto语句.

【例题分析】

一、多项选择题

例3-1 如有以下定义和输入语句,若要求al、a2、c1、c2的值分别为20、60、A、B,则下列数据输入方式中正确的是_。 int a1,a2; char c1,c2;; cin>>a1>>c1>>a2>>c2;

A.20A ┗┛60B B.20,A,60,B C. 20┗┛ A┗┛ 60┗┛ B D.20A60B E.2060B

注:此处┗┛为空格符,<CR>为回车键符,下文同。

解:C+十语言没有专门的输入/输出语句,其输入/输出可通过输入/输出流来实现。cin不能将输入的空格赋给字符型变量,空格和回车键均作为输入字符之间的分隔符;字符型变量只能容纳一个字符,整型数只能由数字组成;逗号不能作为分隔符。

正确答案:A、C、D、E。

例3-2 设有语句float PI= 3.14;,若用科学表示法输出为3.140000e+000则下列正确的表达式为__ A.cout<<PI<<endl;

B.cout.setf(ios:: scientific,ios::floatfield);cout<PI<<\"\\n\"; C.printf(\"%12.10f\\n\",PI); D.printf(\"%e\n\",PI);

解:C+十语言除用输出流输出数据外,还可用C语言的输入/输出函数,但需包含stdio.h,其输出格式与C+十输出流格式不同:C+十中可用预定义的格式控制函数定义输出格式,也可以用ios类的成员函数进行格式控制。若学用科学表示法输出数据,必须用ios类成员函数 setf设置状态标志。printf函数必须用e格式符才可以输出科学表示法形式的数据。 正确答案:B、D。

二、填空题

例3-3 以下程序的输出结果为_____________ #include<iostream.h> void main() {

short i; i=-6;

cout<<"oct="<<oct<<i<<\"dec\" <<dec<i<<\=\"<<hex<<i<endl: }

9

《C++面向对象程序设计》 函授自学指导书

解:i为short 类型,占用2字节内存,而oct、dec、hex是C+十中预定义的格式控制函数控制输入/输出数据的格式。答案为 oct=177772, dec=-6, hex= fffa。

例 3-4 以下程序的输出结果为 #include<iostream.h> void main() {

int i=66; char c='A';

cout<<\"i=\"<<(char)i<<\}

解: 本程序采用了强制型转换符,将i转换为字符型数据输出,又用格式控制函数将字符型数据转换成数值型数据输出。答案为i=B,C=66a 例3-5 以下程序的输出结果为___________ #include void main() {

int i=0,x=0,y=0; do {

i++;

if(i%3!=0) { x+=i;i++; } y+=i++; } while(i<5),

cout<<\"x=\"<解:x = 5 y = 7

例3-6 以下程序的输出结果为_________ #include void main() {

int x, y=10; while(x=y-l) { y-=2;

if(y%3==0) {

x++; continue; }

else if(y<4) break; x++; }

cout<<\"x=\"<解: 输出结果是: x=3 y=2

例3-7 以下程序的输出结果为______________ #include void main() { int i,j,m;

for(i=1;i<4;i++) { for(j=l;j<7;j++)

10

《C++面向对象程序设计》 函授自学指导书

{ if(j= =4) break; m=i*j;

cout<cout<}

解: 运行结果如下:

l×l = 1 l×2 = 2 l×3 = 3 2×l = 2 2×2 = 4 2×3 = 6 3×1 = 3 3×2 = 6 3×3 = 9

注意:当j的值为4时,结束的是内层循环,外层for循环继续执行。 例3-8 以下程序的输出结果为___________ #include void main() { int i,j,m;

for(i= l;i<4;i++) { for(j=1;j<7;j++)

{ if(j = = 4) continue; m=i *j;

cout<cout<解:运行结果如下:

1×l = l l×2=2 l ×3=3 1×5=5 l ×6=6 2×1 = 2 2×2=4 2×3= 6 2×5 = l0 2×6= l2 3×l =3 3×2= 6 3×3=9 3×5 = l5 3×6= 18

注意: continue结束本次循环,即当j的值为4时,内层循环体的条件语句后面的部分不执行,循环变量j自加,执行下一次内层循环。

例3-9 输入一个自然数,输出其各因子的连乘形式。如输入12,输出12=12×2×3的形式,请填空。 #include void main() {

int i=2, n;

cout<<\"输入一个自然数:\"; cin>>n;

cout<if(n%i= =0) {

cout<<'*'<______1_________; }

else i++;

11

《C++面向对象程序设计》 函授自学指导书

} while(____2_____);

}

解: ①n=n/i;②n!=1

三、编程题

例 3-10 编程实现如下所示的函数关系式。已知 X,求 y的值。

x (x<1) y= x+5 (1≤x≤10)

x-5 (x≥ l0)

解:该函数实质是一个分段函数,即根据x的不同取值范围,由相应的函数式求y的值。

(1)使用缺省else的if语句形式 #inc1ude void main() {

float x,y;

cout<<\"Enter a number: \"; cin>>x ; if(xif(x>= l &&x=10) y=x-5;

cout<<\"y= \" <(2)用条件语句的嵌套形式实现 #inc1ude void main() {

float x,y;

cout<<\"Enter a number:\"; cin>>x; if(x<1) y=x;

else if(x< 10) y=x+5;

else y=x-5;

cout<< \" y= \" <例3-11 根据输入的年月,求出该年该月的天数。

解:本题要根据月份来讨论天数,如是大月(1,3,5,7,8,10,12)则天数是31,如是小月(4,6,9,11)则天数是30;如是2月;要看该年是否闰年,是闰年则为29天,非闰年则为28天,显然本程序采用多分支选择结构。具体程序如下:

#include #inc1ude void main() {

int year,month,days; cout<<\"Enter the year: \"; cin>>year;

cout<<\"Enter the month:\";

12

《C++面向对象程序设计》 函授自学指导书

cin>>month; switch(month) {

case 1: case 3: case 5: case 7: case 8: case 10:

case l2:days=3 1;break; case 4: case 6: case 9:

case 11:days=30;break;

case 2: if((year%4==0& & year%100!=0) || year%400= =0) days=29;

else days=28; break;

default:cout<<\"Input error ! \"<cout<<\"year: \" <}

例3-12 求下列分数序列的前15项之和。 2/1,3/2,5/3,8/5,13/8,21/13,...

解:根据题意可采用累加方法,为此需定义一个存放累加结果的变量sum,累加的过程自然是通过循环结构来实现,循环变量i的取值范围是1到15,且循环变量表示当前的数列项数;在循环体内不仅要计算数列第i项的值,还要计算前i项的累加和。数列的规律:从第2项开始;每一项的分母是前一项的分子,而分于是前一项的分子分母之和,即第i-1项为a/b,则当i>l时,第i项为(a+b)/a。程序如下:

(l)用while语句实现。 #include void main()

{ float sum,t,a,b;

int i;

a=2;b= l;i= 2 ) t=a/b; sum=t; while(i<=5)

{ a=a+b; //求第i项的分子 b=a-b; //求第i项的分母 t=a/h; //求第i项的值 sum+=t; //求第i项的和 i++;

}

cout<<\" sum=\" <(2 ) 用for语句实现. #include void main()

13

《C++面向对象程序设计》 函授自学指导书

{ float sum,t,a,b;

int i,

a=b= 1.0, sum=0.0; for(i= 1;i<= 15;i++)

{ a=a+b; //求第i项的分子 b=a-b,; //求第i项的分母 t=a/b; //求第i项的值 sum+=t; //求第i项的和

}

cout<< \"sum= \" << sum<(3 )用do-while语句实现 #include void main()

{ float sum,t,a,b; int i=l,

a=b=1.0;sum=0; do

{ a=a+b; //求第i项的分子 b=a-b; //求第i项的分母 t=a/b; //求第i项的值 sum+=t; //求第i项的和 } while(++i<= 15);

cout<< \"sum=\" <例3-13 正整数n从键盘输人,计算5n的值。

解:计算5n可用循环语句实现,本例仅以while语句实现。 #include void main() {

int i=1,n;

float resuIt=1.0; cout<<\"输入n:\"; cin>>n; if(n) {

while(i<=n) {

result*=5.0; i++; }

cout<<\"结果是: \"<}

例3-14 1-l/2+1/3-1/4+„+l/99-1/100的值。 解:本题仅以for语句实现。 #include void main() {

float sum=0.0, s=1 .0;

14

《C++面向对象程序设计》 函授自学指导书

for(int i=l;i<=l00;i++) { sum+=s/i; s=-s, }

cout<<\"结果是: \"<例3-15 输入一行字符,将其中的两种字符 ‘C’和‘+’显示出来,而对其他字符不显示,同时统计出其他字符的个数。 解: #include #include void main() {

char ch; int i=0;

while ((ch=getchar() ) ! ='\\n' ) { if(ch!='C'&&ch!='+') { i++;

continue; }

cout<cout<<\"其他字符的个数为:\"<例3-16 从键盘输入某班若干名学生一门课程的成绩,编程找出最高分和最低分,并统计全班平均成绩。

解:要求程序具有灵活性,程序中参加统计的学生人数应随具体情况而定,不应固定,若以输入负数作为统计结束条件,则程序如下: #include void main() {

float score;max;min;sum=0.0; int num=0;

cout<<\"输入一个成绩!\"; cin>>score;

max=min= score; whi1e(score>=0) {

if(score>max) max=score; if(scorecout<<\"输入一个成绩!\"; cin>>score; }

if(num) {

cout<<\"共统计 \"<15

《C++面向对象程序设计》 函授自学指导书

cout<<\"平均成绩是\"<else cout<<\"无输入!\"<}

例3-17 从键盘不断读入字母,如字母为元音字母,则输出其相应的大写字母,否则结束程序

解: #include void main() {

char ch; int quit=0; do {

cout<<\"\\n 输入一个字母:\";

cin>>ch; switch(ch) {

case 'a':cout<<'A'; break; case 'e':cout<<'E'; break; case 'i':cout<<'l'; break; case 'o':cout<<'O'; break; case 'u':cout<<'U'; break; default: quit=1; break; }

} while(!quit); }

例3-18 模拟计算器进行加、减、乘、除数学运算。要求当输入两个操作数和运算符后,输出运算结果。一次运算结束后询问用户是否继续,用户根据需要可继续进行运算。

解:

#include void main() {

char op; char quit='y'; float dl;d2;

while(quit= ='y'|| quit= ='Y') {

cout<<\"输入:第一个操作数;运算符和第二个操作数\"<>d1>>op>>d2; switch(op) {

case '+': cout<break;

case '-': cout<break;

case '*': cout<cout<<\"输入错误! \"<16

《C++面向对象程序设计》 函授自学指导书

else

cout<D.int a[ ]={0, 1,2,3,4,5 };

解:根据数组定义和初始化情况,数组类型与所赋数据的类型应一致,指定的数组长度应大于或等于花括弧中的数据个数,对数组长度可省略。 正确答案:D。

例4-2 设有定义语句inta[2][4]]:则以下叙述不正确的是_。 A. a数组可以看成是由 a[0]、a[1]两个元素组成的一维数组 B. a[0]代表一个地址常量

C. 元素a[0]是由4个整型元素组成的一维数组 D. 可用a[0]=5;的形式给数组元素赋值

解:C++对二维数组的处理是将其看作一个特殊的一维数组,即这个数组中每个元素又是一个一线数组。所以二维数组a可认为是由两个元素a[0]。a[1]组成的一维数组,而数组元素 a[0]和 a[1]又是由 4个int型元素组成的一维数组。C+十规定了数组名代表地址常量,其值是不可改变的,故赋值语句a[0]=5:是非法的。

正确答案:D。

例4-3 若有说明int a[3][4];,则对a数组元素的非法引用是_。 A. a[0][2*1] B. a[0][4] C. a[4-2][0] D. a[1][3]

解:引用二维数组元素的格式为:数组名[下标表达式1][下标表达式2],而下标表达式可以是常量、变量,但其值必须是确定的整数且在该数组的定义范围之内。

正确答案;B。

例4-4 若有以下定义和语句,则输出结果是_。 char a, s[l0], s=\"abcd\"; a=s; cout<A. abcd B. a C. abcd┗┛┗┛┗┛┗┛┗┛ D. 编译出错

解:字符数组的赋值,不能通过赋值语句实现,而是通过初始化或Strcpy函数来实现。

正确答案:D。

例4-5 能判断字符串s1是否大于字符串s2的是_。 A. if(sl>s2) B. if(strcmp(s1,s2)) C. if (strcmp(sl, s2)>0) D. s1>s2

解:两个字符串比较必须使用字符串比较函数strcmP(字符串1,字符串2)。比较的结果:相等时返回以0;大于时返回正整数;小于时返回负整数。 正确答案:C。 二、填空题

例4-6 若有定义 int a[3][4]={ { 1,2},{0},{4,6,8,l0} ),,则初始化后a[1][2]得到的初值是_,对[2][1]得到的初值是_。

解:在定义的同时对数组元素进行初始化,可以对所有元素赋初值,也可只对部分元素赋初值;其余元素为0。根据数组中元素排列的顺序以行为单位进行存放,定义式右边的数据是以{}作为行元素进行组织的。故 a[l][2]得到的初值是0,a[2][1]得到的初值是6。

21

《C++面向对象程序设计》 函授自学指导书

例4-7 语句cout<解:按照C+十中转义字符的规定,在字符串\"\\\\\\\n\\'\\065\\08AW\"中,含有\、\\\\、\\n、\\'、\\065转义字符,分别表示单个字符;\\0也是转义字符,是宇符串结束标志,系统认为字符串到此结束,不计其后的8、A、W。 正确答案:5。

注意:若将 8改为 7,而\\07却是一个字符,加上 A、W,此字符串的长度是8。

例4-8 以下程序的输出结果是_。 #include \"iostream.h\" #include\" string.h\" void main() {

char str[50]=\"xyz\strcpy(str+2, strcat(p1 +2,p2+1)); cout<解:由于字符数组名str、pl、pZ表示地址,同理表达式str+2、p1+2、p2+1 的值也是地址,str+2表示字符串“xyz”中字符z的地址,p1+2表示字符串“abcd”中c的地址,p2+l表示字符串\"ABCD\"中字符'B'的地址,分别代表的字符串为“z”、\"cd\"、“BCD”。调用函数strcat(p1+2,p2+1)得到字符串“cdBCD”,调用strcpy()后,将刚才“cdBCD”拷贝到str中以‘z’为起始地址的存储单元中,因此覆盖了str 中从'z'开始的存储单元中的数 据,

正确答案:xycdBCD。 三、编程题

例4-9 先定义一个含有30个整型元素的数组,依次赋予从2开始的偶数,然后将按顺序每五个数的平均值放在另一个数组中,并要求按每行3个数输出结果。

解:根据题意,可定义一维整型数组a[30]用于存放初始数据和数组b[6]用于存放平均值,临时变量sum用来存放5个元素之和。以i(初值为0,终值为29)作为循环变量,用for循环通过a[i]=2*i+2给数组a赋值;以i作为循环变量,表达式i%5==0将a的30个元素分成6组,分别求出和sum,以j为数组b的下标,用while循环来实现b[j]为a的5个元素之平均值。 程序如下:

#inc1ude \"iostream.h\" void main() {

int a[30],i,j=0; float sum=0,b[6];

for(i=0,i<30,i++) a[i]=2*i+2; //给a数组元素赋值 cout<<\"30 个整数为:\\n\";

for(i=0;i<30;i++) cout<while(i<30){ //求 a中每 5个元素的平均值,放入 b数组中

sum+=a[i];i++;

if(i%5= =0) { //5个元素为一组,求平均值

b[j]=sum/5; sum=0; j++; //sum必须置为0,为下一组数求和作准备

22

《C++面向对象程序设计》 函授自学指导书

}

}

cout<<\"每五个数的平均值:\"; for(i=0;i<6;i++){

if(i%3==0) cout<<'\\n';//每行输出 3个数 cout<例 4-10 通过循环按行顺序为一个 5×5 的二维数组赋 1~25 的自然数,然后计算并输出该数组的左下三角元素之和。试编程。

解:可以利用双重循环实现二维数组的赋值,即用外循环控制行下标i,内循环控制列下标j,在循环体中数组元素a[i][j]=n,(n的初值为1,每赋值一次加 1);同样利用双重循环实现左下三角元素之和的计算,外循环的行下标i从0~4,内循环的列下标j的终值为可变数,其规律是与行下标值正好相等,即 j的值从 0变化到 i,在循环体内对元素a[i][j]进行累加,并存放在sum中。程序如下: #include \"iostream.h\" void main () {

int a[5] [5],i,j,n=1,sum=0; for (i=0;i<5;i++)

for(j=0;j<5;j++) a[i][j]=n++;

cout<<\"数组的左下半三角:\\n\"; for(i=0;i<5;i++) { for(j=0;j<=I;j++){ sum+=a[i][j];

cout<cout<<'\\n'; }

cout<<\"数组左下三角的元素之和: \"<例 4-11 设字符串a中的字符按其 ASCⅡ码递增排序,从键盘输入一个字符,用折半查找法找出原字符在a中的位置,若该字对不在a中,则打印出**。试编程。

解:拆半查找法的算法原理:先检索当中的一个数据,看它是否为所需的数据,若不是,则判断要找的数据去在当中数的哪一边,下次就在这个范围内查找,重复此过程直全找到为止。设三个变量top、mid、bot分别指向长度为N且已排序数据a的头、中间和尾的位置,需查找数据为c, 则具体算法为: (1 )令 top = 0, bot=N-l, mid= (top+bot) /2。

(2)若a[mid] = c. 则找到了该数据,查找结束。

(3)若 a[midl>c, 则c在mid的左侧,令新的bot=mid-1,转(5)。 (4) 若 a[midl(6)若 top>bot, 则表明要查找的数据c不在数组a中。 程序如下:

#include \"iostream.h\" #include\" string.h\" void main()

23

《C++面向对象程序设计》 函授自学指导书

{

char a[ ]=\" adfgikmnprs\int top,bot,mid;

cout<<\"已排序的字符串 : \"<>c;

for(top=0;bot=strlen(a) -1;top<=bot;) { //用srtlen(a)计算a中的实际字符个数 mid=(top+bot)/2;

if(c= =a[mid] ) { cout<a[mid]) top=mid+1;

else bot=mid-1; }

if(top>bot) cout<<\" * *\\n\"; }

【思考题】

一、选择题

1.若有以下说明,则数值为4的表达式是_。 int a[ 12]= { 1,2,3,4,5,6,7,8,9, l0, 11, l2 }; char c= 'a',d, g;

A. a[g-c] B. a[4] C. a['d'-'c'] D. a['d'-c] 2.以下程序的输出结果是_。 #include\" iostream.h\" void main() {

int n[2]= { 0},i,j,k=2; for (i=0;ifor(j=0;jA. 不确定的值 B. 3 C.2 D.1 3. 以下对二维数组的正确说明是_。 A.int a[3][ ] B. float a(3,4)

C. double a[1][4] D. float a(3)(4)

4.若有说明inta[3][4];则对 a数组元素的正确引用是_。 A. a[2][4] B. a[1,3] C. a[1+1][0] D. a(2)(1) 5.以下能对二维数组b正确进行初始化的语句是_。 A. int b[2][3] = { { 1,1 },{2,2},{3,3 } }; B. int b[3][ ] = { { 1 },{2},{3}}; C. int b[ ][ ]= { 1,2,3,4,5,6};

D. int b[ ] [3] = { { 1,1,1,},{2,2},{3} };

6.若有定义语句 int m[ ][2]={1,3,5,7,9}; 则以下叙述正确的是_。

A. 该语句存在语法错误

B. 该语句等价于int m[3][2l = { 1,3,5,7,9}; C. k语句等价于int m[ ][2] = { { 1,3,5},{7,9} };

D. 该语句等价于int m[2][2] = { 1,3,5,7,9};

24

《C++面向对象程序设计》 函授自学指导书

7. 以下程序的输出结果是______ #include \"iostream.h\" void main() {

int i,x[3] [3]={ 1,2,3,4,5,6,7,8,9 }; for (i=0;i<3;i++) cout<A.159 B.147 C.357 D.369 8. 以下程序的输出结果是____ #include \"iostream.h\" void main() {

int a[3] [3]={ { 1,2},{ 3,4}. { 5,6} },i,j,s=0; for (i= 1,i<3,i++)

for(j=0;j<=l;j++)s+=a[i][j]; cout<A. l8 B. 19 C.20 D. 2l 9.下面对S初始化不正确的是____

A.char s[5l={ \"abc\" }; B.char s[5]={ 'a','b','c' }; C.char s[5]=\" \"; D.char s[5]=\"abcdef\"; l0.下面程序段的运行结果是_________

char c[5]={' a', 'b', '\\0', 'c', '\\0'}; cout<11.当运行以下程序时,有三行输入,且每行均从第一列上开始,则程序的输出结果是____

#include \"iostream.h\" #define N 6 void main() {

char c[N];int i=0;

for(i=0;iA.abcdef B. a C.a D. a b b b c cd cdef d e f

12.对两个数组a和b进行如下调始化,则叙述正确的是。 char a[ ] = \"ABCDEF\";

char b[ ] = { 'A', 'B', 'C', 'D', 'E', 'F};

A.a和b数组完全相间 B.a和b数组长度相同 C.a和b中都存放字符串 D.a数组比b数组长度长

25

《C++面向对象程序设计》 函授自学指导书

13.下面程序段的运行结果是_。

char c[ ]=\" \\\v\\\\\\0will\\n\"; cout<A.4 B.3 C.9 D.字符串中有非法字符,输出值不确定 14. 若有以下定义和语句,输出结果是_。 char s[6]; s= \"abcd \"; cout<< '\\\" '<A.\"abcd\" B.\"abcd┗┛\" C. \\ \"abcd┗┛\\\" D. 编译出错 15.判断字符率 a 和b是否相等,应当便用_。

A.if(a= =b) B.if(a=b) C.if(strcpy(a,b)) D.if(strcmp(a,b)) 16. 下面程序段的运行结果是_。 char a[7]= \"abcdef\"; char b[4]= \"ABC\"; strcpy(a,b); cout<17.下面程序段是输出两个字符串中对应位置相等的字符;请选择填空。 char x[ ]= \"programming\whi1e (x[i] != '\\0'&&y[i] !='\\0')

if(x[i]==y[i]) cout<<__________; else i++;

A.x[i++] B.y[++i] C.x[i] D. y[i]

18.下面程序的功能是将字符串S中所有C字符删除、请选择填空。 #include \"iostream.h\" void main() {

char s [81]; int i,j; cin>>s;

for (i=j=0;s [i] !='\\0';i++) if(s[i] !='c') _________ s [j] ='\\0'; cout<A..s[++j]=s[i] B.s[j++]=s[i] C.s[j]=s[i];j++ D.s[j]=s[i]

19.下面程序的功能是从键盘输入一行字符,统计其中有多少个单词,单词之间用空格分隔。请选择填空。 #include \"iostream.h\" #include \" string.h\" void main() {

char s[80],c1,c2=''; int i=0,num=0; cin.getline(s,80); while(s[i] !='\\0') { c1=s[i]; if(i= =0)c2=' '; else c2=s [i--l ]; if(________)num++; i++; }

26

《C++面向对象程序设计》 函授自学指导书

cout<<\"There are\" <}

A.c1= =\"&&c2= =\" B.c1!=\"&&c2= =\" C.cl = =\"&&c2!=\" D.c1!=\"&&c2!=\" 20.下面程序的运行结果是_。 #inc1ude \"iostream.h\" void main() {

char ch[7]={\" 12ab56\" }; int i,s=0;

for(i=0;ch[il>='0'&&ch[i]<='9';i+=2)s=10*s+ch[i]-'0'; cout<< s; }

A.1 B. l256 C.l2ab56 D. 1 2 5 6

21.当运行以下程序时;从键盘输入 AhaMA Aha,则下面程序的运行结果是_。

#include \"iostream.h\" #include \"string.h\" void main() {

char s [80],c='a'; int i=0;

cin. getline(s,80); while(s[i] !='\\0') { if(s[i]= =c) s[il=s[i]-32;

else if(s[i]= =c-32) s[i]=s[i]+32; i++; }

cout<A.ahAMa B.AhAMa C.AhAMa ahA D.ahAMa ahA 二、填空题

22. 若有以下定义double w[10];则 W 数组元素的下标的上限是_,下限是__。 23. 以下程序共输出_行,最后一行有_个数。 #include \"iostream.h\" #include \"iomanip.h\" #define N 24 void main() {

int aa[N],I;

for(i=0;icout<27

《C++面向对象程序设计》 函授自学指导书

cout<<'\\n';

}

24.下面程序的运行结果是。 #include \"iostream.h\" void main() {

int arr[l0],i,k=0;

for(i=0;i<10;i++) arr[i]=i; for(i=0;i<4;i++) k+=arr[i]+i; cout<25.以下程序统计从终端输入的字符中每个大写字母的个数;num[0]中统计字母 A的个数,num[1]中统计字母 B的个数,其他依此类推。用#结束输入,请填空。 #include \"iostream.h\" #include \"ctype.h\" void main() {

int num[26]= { 0 } ,i,char c; cin>>c;

while(c !='#') {

if(isupper (c)) num [___________] + +; __________________ }

for(i=0;i<26;i++) if(num[i]) {

c=i+'A'; cout.put(c);

cout<<': '<26.若程序需要对 30个学生的成绩进行处理,每个学生有 5门课的成绩,要求放在一个二维数组中,第一个学生的第一门课的成绩放在下标为1的元素中,其他类推,写出合理的数组定义语句___________。

27.以下程序将M * N的二维数组X转置(行列互换)后存入N×M的二维数组y中,请填空。

#include \"iostream.h\" thnclude \"iomanip.h\" #define M 2 #define N 3 void main() {

int x[M] [N]={ 1,2,3,4,5,6},y[Nl[M]; int i,j;

for(i=0;lfor(j=0;jfor(i=0;i28

《C++面向对象程序设计》 函授自学指导书

for(j=0;jfor(i=0;i<_____;i++) {

for(j=0;j<________;j++) cout<}

28.以下程序的功能是计算N ×N方阵的主、次对角线元素之和,请填空。 #include \"iostream.h\" #include\" iomanip.h\" #define N 3 void main() {

int x[N] [N]={ l,4,7,2,5,6,3,9,8 },s1 =0,s2=0,i,j; for(i=0;ifor(j=0;jfor(i=0;ifor(j=N-1;j>=0;________ ) if((i+j)==N-1) s2+=________;

cout<29.以下程序的输出结果是_。 #include \"iostream.h\" #include \"iomanip.h\" #define N 3 void main() {

int arr[N][N]={ { 100,200,300},{28,72,-30},{-850 }; int i,j,row,col,m; m=arr[0] [0]; for(i=0;iif(arr[i][j]cout<30.以下程序实现在N行M列的二维数组中,找出每一行上的最大值。请填空。

#include \"iostream.h\" #define N 3 #define M 4 void main() {

int x[N] [M]= { 1,5,7,4,2,6,4,3,8,2,3, 1 };

29

《C++面向对象程序设计》 函授自学指导书

int i,j,colum;

for(i=0;icolum=__________; for(i= 1;jif(x[i][colum]cout<<\"The max value in line \"<}

31. 以下程序实现在N×N方阵中找出主、次对角线上的最大值;请填空。 #include \"iostream.h\" #define N 3 void main() {

int x[N][N]={ 1,5,7,4,2,6,4,3,8 }; int i,j,row=0,col=0; for(i=0;iif(x[row] [col]if(x[row][col]cout<<\"The max value is x[\"<32. 以下程序的输出结果是_。 #include \"iostream.h\" void main() {

char s[ ]=\" 12134211\"; int v1=0,v2=0,v3=0,v4=0,k; for(k=0;s[k];k++) switch(s [k] ) { default: v4++; case 'l' : v1++; case '3' : v3++; case '2': v2++; }

cout<<\" v1=\" <33.以下程序的输出结果是_。 #include \"iostream.h\" void main() {

char w[ ] [ 0]= { \"ABCD\int k;

for(k=1;k<3;k++) cout<34.以下程序的输出结果是_。 #include \"iostream.h\" #include\" string.h\"

30

《C++面向对象程序设计》 函授自学指导书

void main() {

char p1[20]=\"abc\; strcpy(str+2,strcat(p1,p2)); cout<35.以下语句的输出结果是_。 char a1p[3] [4]={\" abc\int i;

for(i= 1;i<2;i++) cout<36.以下程序运行后,如果从键盘输入: C++ [cr] BASIC [cr] Quick [cr] Ada [cr] Pascal [cr]

则程序的输出结果是_。 #include \"iostream.h\" #include \"string.h\" void main() {

char str[10],temp[ l0]; int i;

cin. getline(temp, l0); for(i=0;i<4;i++) { cin.getline(str, l0);

if(strcmP(temp,str)<0) strcpy(teInP,str); }

cout<37. 以下程序的输出结果是_。 #include \"iostream.h\" #include \"string.h\" void main() {

char b[30];

strcpy(&b[0],\"gh\"), strcpy(&b[1],\"def\"), strcpy(&b[2],\"abc\"), cout<38.以下程序求字符串的长度,请填空。 #include \"iostream.h\" #include \"string.h\" void main() {

char str[80]; int i; cin.getline(str,80);

for(i=0;___________i++); cout<31

《C++面向对象程序设计》 函授自学指导书

}

39.以下程序的功能是从键盘输入一字符串,按其反序输出,请填空。 #include \"iostream.h\" #include \"string.h\" void main() {

char str[80l, int i; cin.getline(str,80);

for(i=______;i>=0,i--)_______; }

40. 以下程序用来对从键盘上输入的两个字符串进行比较,然后输出两个字符串中第一个不相同字符的 ASCll码之差。例如:输入 abcD和abcd;则输出为-32。请填空。

#include \"iostream.h\" #include \"string.h\" void main() {

char str1[l00],str2 [l00]; int i=0;

cout<<\"Input string 1:in\"; cin. getline(str l, 100); cout<<\"Input string 2:\\n\"; cin. getline(str2, 100);

while((strl [i]= =str2[i])&&(strl [i] !=_________ )) i++; cout <_________; }

三、编程题

41.从键盘输入若于整数(数据个数少于50个),计正数、负数和零的个数。 42.找出一个二维数组中的鞍点,即该位置上的元素在该行上为最大,在该列上为最小。没有较点的给出相应的提示信息。

43.从键盘输入一字符串,对该字符串中的字符按其ASCll码从大到小的顺序排序后输出.

44.按B、F、K、M、Q、Y顺序输入字母到数组中,再输入一字母插入到此有序数列中,插入后,数组中的字符仍然有序。请对程序运行四次,分别插入字母A、M、J、Z

45.下面是一个 5 × 5阶螺旋方阵、试编程打印出此形式的 n ×n(<10)阶方阵(顺时针方向旋进)。 1 2 3 4 5 16 l7 l8 l9 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9

46.从键盘输入两个字符串a和b, 要求不用库函数strcat把串b的前五个字符连接到串a中,如果b的长度小于5,则把b的所有元素都连接到a中。

32

《C++面向对象程序设计》 函授自学指导书

第五章 函数与编译预处理 【学习要点】

1. 掌握C+十程序中函数的定义方法和函数调用规则。

2. 掌握C+十程序中主调函数和被调函数之间进行数据传递的规则。 3. 掌握函数的返回值和它的类型。

4. 理解函数违归调用的过程,掌握简单递归算法的实现。

5. 掌握具有缺省参数值和参数个数可变的函数的概念、定义方法和调用规则。 6. 掌握内联函数的概念和应用。

7. 明确局部变量和全局变量的作用域和生存期的概念,能正确区分和使用局部变量和全局变量,了解局部变量和全局变量与存储分类的关系。

8. 理解宏的概念,掌握定义无参宏和带参宏的方法;了解文件包含的概念,掌握其用法。

9. 理解函数重载的概念及使用场合。掌握正确编写重载函数的方法,避免出现二义性。

10. 了解多文件程序的编译和连接方法。

【例题分析】

一、选择题

例5-1 以下函数的类型是____1_____,函数的返回值是____2_____。 func(flontx){cout<<x*x<<endl;=

①A.与参数 x的类型相同 B.void类型 C. int类型 D. 无法确定

② A.0 B.无确定值 C.1 D.出错 解:函数名前面的类型标识符若省略,则隐含为int型。 ①的正确答案:C。

函数中因没有return语句,执行到函数末尾自动返回主调函数,返回的是无确定值。

②的正确答案:B。

例 5-2 若有以下函数调用语句,则其实参的个数是____。 fun(a+b,(y=9,y*x),fun(y,n,k); A.3 B.4 C.5 D.6

解:实参可以是常量、变量、表达式。本题的实参分别为算术表达式,逗号表达式和函数表达式3个。 正确答案:A。

例5-3 以下程序的输出结果是_ #include\"iostream.h\" void main() {

int x=1,y=2;

void s_value(int y,int x); s_value(y,x);

cout<<\"x=\"<<x<<\",\"<<\"y=\"<<y<<endl;

33

《C++面向对象程序设计》 函授自学指导书

void s_value(int x,int y) {

cout<<\"x=\"<<x<<\",\"<<\"y=\"<<y<<endl; x=3; y=4; }

A.x=1,y=2 B.x=1,y=2 x=1,y=2 x=3,y=4 C.x=2,y=1 D.x=2,y=1 x=3,y=4 x=1,y=2

解:由于函数调用时实参与形参之间 的数据传递只与位置有关而与变量名无 关,且是“单向”的“值传递”方式。该 程序中s_value函数调用的数据传递如图 5-1所示,故在函数s_value中的cout语 句输出:x=2,y=l。尽管该函数对x、y 分别赋了新值3、4,由于函数参数间数 据传递的特点,且参数非全局变量,形参 的变化不会影响到实参,返回后,main 函数的。ul语句输出:x=1,y=2。 正确答案:D。

例5-4 以下叙述正确的是_。

A.建立内联函数的主要目的是提高程序的执行效率

B.建立内联函数的主要目的是减少程序文件所占用的内存 C.内联函数的参数传递关系与一般函数的参数传递关系不同 D. 任意函数均可定义成为内联函数

解:内联函数是使用更多的存储空间,减少执行时间,即采用空间换取时间,以提高程序执行效率,当多次调用同一内联函数时,程序会增大占用空间。除了在函数体内含有循环语句、swich语句的函数和递归函数不能定义为内联函数以外,其余均可定义成内联函数。内联函数参数传递关系与一般的函数相同。

正确答案:A。

例5-5 以下叙述正确的是_。

A .C+十程序中各函数之间不允许直接递归调用也不允许间接递归调用 B .C+十程序中各函数之间允许直接递归调用但不允许间接递归调用 C .C+十程序中各函数之间不允许直接递归调用但允许间接递归调用 D.C+十程序中各函数之间既允许直接递归调用也允许间接递归调用

解:C+十程序的函数的递归调用,即在调用一个函数的过程中可直接或间接地调用该函数本身。

正确答案:D。

例5-6 以下程序的输出结果是_。 #include void main() {

int sub(int b[ ]);

int a[4]= { 1,2,3,4 } j,x; for(i=0;i<4;i++) {

34

《C++面向对象程序设计》 函授自学指导书

x=sub(a), cout<}

int sub(int b[ ]) {

static int t=3; int result; result=b[tl; t--; return(result); }

A. 1234 B. 4321 C.0000 D. 4444

解:由于本题在Sub函数以数组作为函数参数,形参和实参之间数据传 递为“地址传递”;该函数说明了t为静态局部变量,则在整个程序执行期 间始终固定存放在静态存储区中,但只在该函数中起作用,且在开始执行时 初始化,其后保留其运行结果。本题中四次进入sub函数,t的值分别为3、 2、1、0,根据相应的sub函数返回值易得输出结果是4321。 正确答案:B。

例5-7 以下程序的输出结果是_。 #include \"iostream.h\" int d=1;

void fun(int p) {

int d=5; d+=p++;

cout<void main() {

lnt a=3; fun(a); d+=a++;

cout<A.9 4 B.9 6 C.8 4 D.8 5

解:局部变量的作用域是从定义的位置起到函数体或复合语句结束为止。全局变量的作用域是从变量定义的位置开始到整个源文件结束为止。若全局变量与局部变量同名;则在该局部变量起作用的范围内,全局变量不起作用。本题d为全局变量,而在fun中定义了d为局部变量,故在该函数全局变量d不起作用,程序运行结果是:8 4。

正确答案:C。 二、判断题

例5-8 int func(int x, int y) {

return(x+y); }

long func(int x, int y) {

35

《C++面向对象程序设计》 函授自学指导书

return(x*y);

}

解:两个函数的参数类型及个数完全一样,仅仅是返回值类型不同,不是合法的函数重载。

例5-9 int val(int x1, int y1) {

return(x1*y1); }

int val(int &x2, int &y2) {

return(x2+y2); }

解:引用类型变量的使用与普通变量的使用在形式上是一样的,这使得两个函数的参数类型及个数也是完全相同的,故不是合法的函数重载。

例5-10 int f(int x,int y) {

return(x*y); }

int f(char c 1,char c2) {

return (c1+c2); }

解:这个问题需具体分析。当C+十调用一个函数时,需进行实参与形参的结合,这个结合过程要将调用函数的实参表与每个重载函数的形参表进行比较,如果实参表和一个重载函数的形参表完全匹配,则调用该重载函数;如果没有找到严格的匹配函数,则C+十编译器会试图通过类型转换找到一个匹配函数,则编译器可能发现与多个重载函数匹配,从而造成二义性。如假定函数f(2,2)、f('a','b')是正确的,调用f('a',3)时,编译器无法确定将它转换为 f(int,int)形式,还是 f(char,char)形式,会造成二义性。

三、填空题

例5-11 以下程序的输出结果是___。 #include \"iostream.h\" #define S(a) a*a void main()

{ int x=1, y=2, t;

t=S(x+y);

cout<解:由于宏展开只是简单的字符替换,用实参 x+y代替形参 a,S(x+y)展开后的表达式为x+y×x+y,故程序运行结果是5。需提醒的是在进行宏定义时应注意图括号的正确使用,以满足要求。

例5-12 以下程序的输出结果是_。 #include \"iostream.h\" void main() {

extern int a;

cout<<\"a=\"<36

《C++面向对象程序设计》 函授自学指导书

}

int a=16;

解:在变量说明时,用关键字extern修饰的变量a,称为外部型变量。当全局变量的引用在定义之前,对此需作外部型变量说明。输出结果为a=16。需提醒的是:外部变量的定义和外部变量的说明不同,外部变量的定义(开辟存储单元)只能出现一次,而对外部变量的说明根据需要可出现多次,需用extern进计说明。

例5-13 输入以下三组数据时,①5 4 3 ② 5 4 ③5 。分析下列程序的输出结果_。

#include \"iostream.h\"

float v(float a, float b=10, float c=20), / /A void main() {

float x,y,z;

cout<<\"输入第一个长方体的长、宽、高:\";

cin>>x>>y>>z;

cout<<\"第一个长方体的体积为:\"<<v(x,y,z)<endl; cout<<\"输入第二个长方体的长、宽:\"; cin>>x>>y;

cout<<\"第二个长方体的体积为:\"<<v(x,y)<<endl; cout<<:输入第三个长方体的长:\"; cin>>x;

cout<<\"第三个长方体的体积为:\"<<v(x)<<endl; }

float v(float a,float b,float c){ return a*b*c;}

解:调用具有缺省参数的函数,当不提供相应实参时,以缺省参数作为输入数据。

第一次调用v函数时以5、4、3作为实参,所以第一个长方体的体积为60。 第二次调用v函数时仅提供两个实参x、y的值5、4,形参a、b、c为5、4、20,所以第二个长方体的体积为400。

第三次调用v函数时仅提供实参工的值为5,形参a、b、C分别5、10、20,所以第三个长方体的体积为1000。

四、编程题

例5-14 编写简单的计算器程序。要求用户首先选择+、-、*、/计算种类后,再输入两个数,程序进行相应运算并输出结果,且上述过程可重复。

解:根据题意;该程序应有如下功能: do{

按用户请求工作; }while(继续)

实现该功能的 C+十程序,含 main()、working()和 iscontinue()函数,程序如下;

#include \"iostream.h\" #include \"ctype.h\" void main() {

void working(); //原型声明 int iscontinue(); //原型声明 do{

working(); //函数调用

37

《C++面向对象程序设计》 函授自学指导书

} whi1e(iscontinue());

}

void working() {

cout<<\"please pick an operator(+, -. *,/): \"<>operation;

int firstnum,secondnum;

cout<<\"enter your two integers: \"<>firstnum>>secondnum; cout<<\"the result is:\";

switch(operation) {

case '+':

cout<cout<cout<cout<cout<<\"you entered a bad operator.\"<}//switch end }

int iscontinue() {

char response;

cout<<\"Would you like to do another problem? (Y/N):\"<cin>>response;

response=tolower(response); //变换为小写字母

if(response!='y'&& response!='n') cout<<\"Enter only 'y'or'n':\"; }whiIe(response !='y'&& response!='n');

return(response=='y'?1:0); //若键入'y'则返回1,键入'n'返回0 }

例5-15 编写计算X的y次幂的递归函数GetPower(int x,int y),并在主程序中实现输入输出。

解:根据题意,其递归表达式为;

x; y = l

Getvower(x, y )=

x*GetPower(x, y-l); y> = 2 源程序

#include \"iostream.h\"

long GetPower(int x, int y); //原型声明 void main() {

38

《C++面向对象程序设计》 函授自学指导书

int num,power; long answer;

cout<<\"Enter a number:\"; cin>>num;

cout<<\"number of power:\"; cin>>power;

answer=GetPower(num,power);

cout<<\"The power is: \"<long GetPower(int x,int y) {

if(y= = 1 ) return x; else

return(x*GetPower(x,y-1 ));

}

例5-16 输入一个整数m,判断它能否被3整除。要求利用带参的宏实现该程序。

解:根据题意,整除判断可以利用求余运算实现,定义带参的宏可利用 条件表达式:若能被3整除时为1,否则为0。程序如下: #iclude \"iostream.h\"

#define INT3(x) (((x)%3= =0)?1:0) void main() {

int m;

cout<<\"输入m: \"<>m;

if(INT3(m))//用宏判断m能否被3整除

cout<cout<例5-17 编写一函数将N个整数按其逆序存放,在主函数中实现输入、输出。 解:此题的算法为:对存入数组a的N个整数,将a[0]与a[N—l]对换,再将 a[1]与a[N-2]对换,„„直到将 a[(N—1)/2]与 a[N—int((N—1)/2)]对换。

可用循环结构进行处理,设两个位置变量 i和 j,i的初值为 0,j的初值为 N-1。将a[i]和a[j]]交换,然后使i的值加 1,j的值减1,再将a回和的交换,直到i。(N-1)/2为止。程序如下:

#inc1ude #define N l0 void inv(int a[]); void main() {

int i,a[N]= { 3,7,9, l 1,0,6,7,5,4, l }; cout<<\"The original array'\\n\"; for(i=0,i39

《C++面向对象程序设计》 函授自学指导书

inv(a);

cout<<\"The array has been inverted:\\n\"; for(i=0;i}

void inv(int a[]) {

int t,i,j,m=(N-1)/2; for(i=0;i<=m;i++) { j=N-1-i;

t=a[i];a[i] =a[j];a[j] =t; } }

例 5-18 设计从任意个int型数中找出一个最大数的函数。

解:根据题意,需设计一个参数个数可变的函数max(),其原型为 int max(int n,int num,„)

其中,n为int 型数据的个数,num为第一个int型数据,"…"代表n个参数名。

利用stdarg.h所提供的库函数va_start()、va_arg()、va_end()实现的 函数如下:

#include \"iostream.h\" #include \"stdarg.h\"

int max(int n, int num,...) {

va_list ap; //声明变量ap va_start(ap,num); //初始化ap

int m=num, //m用以保存最大值 for(int i=1;im) m=t; }

va_end(ap); //释放ap return m; }

//下面是max()函数的应用程序 void main() {

int max(int n,int num,...);

cout<【思考题】

一、选择题

1.以下叙述中正确的是_。

A. C+十语言程序的函数中必须有return语句

40

《C++面向对象程序设计》 函授自学指导书

B. 在C+十语言程序中,函数的类型必须进行显式说明 C. 函数中,return语句必须放在函数体的最后

D.C+十语言程序中,return语句中表达式的类型一般应该与函数的类型一致

2.以下正确的函数定义是___。

A.double sub (int x, y ) B.ble sub (int x, int y ) { {

double z; double z; z=x-y; z=x-y; return(z); return(z); } }

C. double sub (int x, int y ) D. double sub (int x, int y ); { { double z; z=x-y; z=x-y; return z; return z; } }

3.若有以下函数调用语句;在此函数调用语句中实参的个数是____。 fun (rec1, rec1+l, (rec1*3, rec2 ) );

A.1 B.2 C.3 D.有语法错误 4.以下程序的输出结果是_。 #include \"iostream.h\"

void fun(int a, int b, int c){a=456; b=567, c=678; } void main() {

int x=l0,y=20,z=30; fun(x, y, z);

cout<A.30, 20, 10 B.10, 20, 30 C.456, 567, 678 D.678, 567, 456 5.以下程序的输出结果是_。 #include \"iostream.h\" int abc(int,int); void main() {

int a=24, b=l6, c; c=abc(a, b); cout<int abc(int u, int v) {

int w; while(v) {

w=u%v;u=v;v=w; }

return(u);

41

《C++面向对象程序设计》 函授自学指导书

A.6 B.7 C.8 D.9 6.以下程序的输出结果是_。 #include \"iostream.h\" void fun(int); void main() {

int w=5; fun(w); }

void fun(int k) {

if(k>0) fun(k-1); cout<A. 5432l B.012345 C.l2345 D.5432l0 7. 以下程序的输出结果是_。 #include ',iostream.h\" int fun(int a) {

int b=0;

static int c=3; b++;

a=b+c++; return (a); }

void main()

int a=2,i,k;

for(i=0;i<2;i++) k=fun(a++); cout<8. 以下程序的输出结果是_。 #include \"iostream.h\" int w=3; int fun(int k) {

if(k= =0) return w; return (fun(k--1)*k); }

void main() {

int w=10;

cout<A.360 B.3600 C.l080 D.1200

42

《C++面向对象程序设计》 函授自学指导书

9. 以下叙述中不正确的是_。

A.一个变量的作用域完全取决于变量定义语句的位置 B. 局部变量可以在函数体外的任何部位进行定义

C. 局部变量的“生存期”仅限于本次函数调用,因此不可能将局部变量的运算结果保存至下一次调用

D. 用static说明一个外部变量,是为了限制其他编译单位的引用,以下叙述中正确的是_。

A. 用#include包含的头文件的后缀不可以是“.a”

B. 在对某个含有错误的头文件进行修改后,包含此头文件的源程序不必重新进行编译

C. 宏名必须用大写字母表示 D. 宏替换不占用运行时间 11. 以下程序的输出结果是_。 #include \"iostream.h\"

#define T(x,y) (x)<(y)?(x):(y) void main() {

int i,j,k;

i=10; j=15; k=10*T(1,j); cout<A.15 B.100 C.10 D.l50 12. 以下不正确的说法为_。

A.在不同函数中可以使用相同名字的变量 B.形参是局部变量

C.在函数内定义的变量只在本函数范围内有效

D.在函数内的复合语句中定义的变量在本函数范围内有效 13. 以下程序的正确运行结果_。 #include \"iostream.h\" #define MAX l0 int a[MAX], i; void sub2() {

int a[MAX],i,max; max=5;

for(i=0;ivoid sub1() { for(i=0;iint i;

for(i=0;ivoid main() {

sub1 (); sub3 (a);

43

《C++面向对象程序设计》 函授自学指导书

sub2(); sub3(a);

}

A. 0 2 4 6 8 l0 12 14 l6 l8 0 1 2 3 4 B. 0 1 2 3 4

0 2 4 6 8 10 l2 l4 l6 18 C. 0 1 2 3 4 5 6 7 8 9 0 l 2 3 4

D. 0 2 4 6 8 10 l2 l4 l6 l8

0 2 4 6 8 10 l2 l4 16 l8

l4.以下程序的正确运行结果是_。 #include \"iostream.h\" void num() {

extern int x,y; int a=l5,b= l0; x=a-b; y=a+b; }

int x, y; void main() {

int a=7,b=5; x=a+b; y=a-b; num();

cout<A.l2, 2 B.不确定 C.5, 25 D.1, 12 l5.以下程序的输出结果是_。 #include \"iostream.h\"

void swap(int &pl, int &p2) { int t;

t=p1; p1=p2; p2=t; }

void main() { int x, y;

x=3,y=4;

cout<<\"x=\"<cout<<\" x=\"<A. x=3 y=4 B. 编译出错 C.x=3 y=4 x=3 y=4 x=4 y=3 二、填空题

16.主调函数为_;被调函数为_。

44

D.无定值

《C++面向对象程序设计》 函授自学指导书

17.内联函数:_。内联函数的特点为_____ 18.以下程序的输出结果是_。 #include

double power(double x, int n); void main(void) {

cout<<\"5 to the power 2 is \"<double power (double x, int n) {

double val = 1 .0; while (n--) val *= x; return(val); }

19.写出以下程序的功能_。 #include int power (int x, int n); void main(void) {

int i;

int value = 0; char ch;

cout << \"Enter an 8 bit binary number \"; for (i = 7, i >= 0; i--){ cin >> ch;

i f (ch = = '1') value +=(power(2,i)); }

cout <<\"Decimal value is \"<int power (int x, int n) {

int val = l;

while (n--) val *= x; return(val); }

20. 若输入5 6;则下列程序的输出为_。 #include void main() {

int a,b;

int fun1(int x,int y); cin>>a>>b;

cout<<\"a. b的平方和 \"<int fun1(int x,int y); {

int fun2(int m);

45

《C++面向对象程序设计》 函授自学指导书

return (fun2(x)+fun2(y));

}

int fun2(lnt m) { return (m*m); } 21. 以下程序的输出结果是_。 #include #incIude

int get_volume(int length, int width = 2, int height = 3); int main() {

int x = l0, y = 12, z = l5; cout << \"Some box data is\";

cout << get_voIume(x, y, z) << endl; cout << \"Some box data is \";

cout << get_volume(x, y) << end1; cout << \"Some box data is is\"; cout << get_volume(x) << endl; cout << \"Some box data is \";

cout << get_volume(x, 7) << endl; cout << \"Some box data is \

cout << get_volume(5, 5, 5) << endl; }

int get_volume (int 1ength, int width, int height) {

return length * width * height; }

22.下面程序中定义的宏SW(type;x;y)实现任意类型的两个数之间的交换、程序中用它对调两个整数和两个双精度数,请填空。

#include \"iostream.h\"

#define SW(type, x, y) {type t, t=x, x=y, y=t,} void main() {

int i= l0,j=20;

double a=2.5, b=9.3;

cout<< \"i=\"<SW(________ i,j); SW(___________ a, b); cout<<\"i=\"<23. 以下程序的输出结果是_。 #include \"iostream.h\" void sub(int, int); int a=l00, b=200, void main() {

int x=10,y=20; sub(x,y); sub(b, a);

cout<46

《C++面向对象程序设计》 函授自学指导书

}

void sub(int x, int y){a= x; x= y; y = a; }

24. 函数del的作用是删除有序数组a中的指定元素x。已有调用语句n=del(a,n,x);其中实参n为删除前数组元素的个数;赋值符左边的n为删除后数组元素的个数。

del(int a[ ],int n, int x) {

int p, i; p=0;

while(x>=a[p] &&p___________________; n=n-1; return n; }

25. 以下程序为计算川名学生的平均成绩。 #include \"iostream.h\"

float average(float array [10]) {

int 1;

float aver,sum=array[0]; for(i=1;___________;i++) sum+=___________; aver=sum/10; return aver; }

void main() {

float score[l0],aver; int i;

cout<<\"Input 10 score: \"; for(i=0;i< l 0;1++) cin>>score [i];

aver=___________;

cout<<\"average score is :\"<26.阅读下列程序,并回答:①运行结果是__________。②若将函数f中的for(j=i+1;j<4;j++)改为for(j=0;j<3-I;j++),则程序运行结果是_。

#include \"iostream.h\" void f(int s[ ][4]) {

int i,j,k;

for(i=0;i<3;i++) for(j=i+1;j<4;j++)

{k=s[i][j];s[i][j]=s[j][i];s[j][i]=k;} }

void main()

47

《C++面向对象程序设计》 函授自学指导书

{

int s[4][4];I;j; for(i=0;i<4;i++) }

for(j=0;j<4;j++) s[i][j]= i - j ; f(s);

for(i=0;i<4;i++) {

cout<cout<27.以下程序的运行结果是________ #include \"iostream.h\" int &f1() {

static int count; return ++count; }

int index; int &f2() {

return index; }

void main() {

f1()=100,

for(int i=0;i<5;i++)

cout<cout<<\"n=\"<cout<< \"inde x= \" <28.以下search函数的功能是利用顺序查找法从数组a的10个元素中对关键字m进行查找、顺序查找的思路是:从第一个元素开始,从前向后依次与关键字比较;直到找到此元素或找到数组尾部时结束。若找到,返回该元素的下标;若找不到,则返回-1。

#include \"iostream.h\" int search(int a[10],int m) {

int i;

for(i=0;i<=9;i++)

48

《C++面向对象程序设计》 函授自学指导书

if(__________)return i; return (-1);

}

void main() {

int a[10],m,i,no; for(i=0;i<=9;i++) cin>>a[i]; cin>>m;

no=search(________);

if(________) cout<<\"OK! \"<三、编程题 29.编写函数:

(1)输入100个职工的姓名和职工号。

(2)按职工号由小到大顺序排序,姓名顺序也随之调整。

(3)要求输入一个职工号,用折半查找法找出该职工的姓名,从主函数输入要查找的职工号并输出该职工姓名。

30.编写函数实现将字符数组s中的字符串反序。主函数实现输入、输出功能。

31.在主程序中提示输入整数n,编写函数用递归的方法求1+2+3+„+n的值.

32.求两个整数的最大公约数和最小公倍数、用一个函数求最大公约数,用另一个函数根据求出的最大公约数求最小公倍数。要求:

(1)用全局变量。将两个整数的最大公约数和最小公倍数都设为全局变量。 (2)不用全局变量。两个整数在主函数中输入,最大公约数和最小公倍数在主函数中输出。

33.对函数名max重载,使其可用于任意类型数据及任意个数参数。

34.利用函数名重载,编写一个包含两个函数的程序;第一个函数返回值是传给它的二个整数的平方和;第二个函数返回值是传给它的二个浮点数和的平方。

第六章 指针 【学习要点】

l. 掌握指针的概念和定义方法。

2. 掌握指针的操作符和指针的运算。 3. 掌握指针与数组的关系。 4. 掌握指针与字符串的关系。 5. 掌握多级指针的含义。

49

《C++面向对象程序设计》 函授自学指导书

6. 掌握指针在函数中的应用。

7. 掌握new和delete操作符作用和使用方法。new可以分配堆空间,delete释放堆空间.而且new能自动调用构造函数创建了相应的类对象,delete自动调用析构函数删除类对象。

【例题分析】

一、填空题

例6-1 根据下面程序及其运行结果,请填空。

#include void main() {

int i=11; long j=40; int k=80; int *pi; 1ong *pj; int *pk; Pi=&i; Pj=&j; pk=&k;

//输出变量的地址

cout << \"\\n address of i:\"<___①_____; cout << \"\\n address of j: \"___②_____; cout << \"\\n address of k: \"<<__③___k; cout << \"\\n pi:\"<<____④____pi; cout << \"\\n Pj:\"<<____⑤____pj; cout << \"\\n pk:\"<<____⑥____pk; cout << \"\\n *pi:\"<<___⑦_____pi; cout << \"\\n *Pj:\"<<___⑧_____pj; cout << \"\\n *pk:\"<<___⑨_____pk; }

程序运行结果如下: address of i:0x8fb1fff4 address of j:0x8fb1fff0 address of k:0x8fb1ffec Pi:0x8fb1fff4 Pj:0x8fb1fff0 pk:0x8fb1ffec *pi:11 *pj:40 *pk:80

解:分析这一程序结果可以看出:1)指针是通过在变量名前加一个“*”来定义的.使用时可以用"*"是加变量名存取指针所指的位置,用运算符"&"取变量的地址.但是不能存取无指向的指针所指内容,这样会导致系统故障。2)变量存储在内存的堆栈中,按照从高地址到低地址的顺序存放,即 i—>j—>k。

正确答案:①~③:&,④~⑥:不填,⑦~⑨:*。

50

《C++面向对象程序设计》 函授自学指导书

例6-2 根据程序的部分运行结果,请给出其他运行结果。 #include void main() {

int a=1,b=2,c=3; int i; int *p; p=&c;

cout<<&a<for(i=0;i<=2;i++)

cout <<\"\\np\"<}

程序运行结果如下: 0x0064FDF0 0x0064FDEC 0x0064FDE8

解:分析这一程序结果可以看出,指针加1后,指针将指向当前变量的后一个变量,如 p指向 c,(p+1)指向 b,(p+2)指向 a。 正确答案为;

p0:3 p1:2 p2:1

例6-3 运行如下程序,其运行结果为。 #include #include void main() {

int *pt_int; float *pt_float; int pig=7,dog=27. float x=1.234,y=4.32l; void *general;

pt_int=&pig; *pt_int+=dog;

cout<<\"\\npig now has the value of \"<<*pt_int<pt_float=&x;

y+=5 * (* pt_float);

cout<<\"y now has the value of \"<const char * name1=\"LiuHua\"; //定义指向常量的指针。

const char * name3=\"CD\"; 值不能被修改,为什么。 //name1 = \"LiuHua\"; name1 =name3;

51

《C++面向对象程序设计》 函授自学指导书

char *const name2=\"LiMing\"; //定义指针常量。

char *const name4=\"AB\"; 指针不能被修改,为什么。 //name2 = name4; *name2=*name4; printf(\" % s\

}

解:分析这一程序,并根据以下理由:1)一个指向常量的指针,所指向的值不能改变,而指针自身可以移动;2)一个常数指针,指针的值不能改变,而指什指向的值可以改变;3)void指针可被赋于其他任何指针类型的值,这样可以在程序中传递数据。可得出程序运行结果如下: pig now has the value of 34 y now has the value of 10.491 AiMing

例6-4 运行如下程序,其运行结果为_。 #include void main() {

int i,*p,a[]={ 2,4,6,8, 10 }; p=a;

for(i=0;i<=4;i++)

cout<<\"\\na[\"<解:分析程序,根据引用数组元素可以有三种不同的方法:使用下标变量:使用数组的固有指针——数组名的间接引用;使用指向数组的指针的间接引用。可得运行结果如下:

a[0]=2,*(a+0)=2,*(P+0)=2 a[1]=4,*(a+1)=4,*(P+1)=4 a[2]=6,*(a+2)=6,*(P+2)=6 a[3l=8,*(a+3)=8,*(p+3)=8

a[4]=10, * (a+4)= 10, * (p+4)= l0

例6-5 运行如下程序,其运行结果为_________。 #include int a[3][4]={ {1,3,5,7},

{9, 11, 13, 15 }, { 17, 19,21,23 } }; main() {

int i,(*b)[4], *p;

b=a+1; //A p=b[0]; //B for(i=l;i<=4;P=P+2,i++) //C

printf(\"%d\\

52

《C++面向对象程序设计》 函授自学指导书

printf(\"\\n\" );

for (i=0;i<=2;i++) {

b=a+i; //D printf(\"%d\\}

printf(\"\\n\"),

}

解:根据题意以及数组和指针的关系,A行表明数组指针b指向二维数组 a的第 1行,即 b[0]指向 a[1][0];B行表明指针 p指向数组 b的首地址;C行修改p的指向,且每次跳过1个数据;D行修改b的指向,每次跳过一行数据。故程序运行结果如下: 9 l3 l7 21 3 ll l9

例6-6 运行如下程序,其运行结果为______。 #inciude struct date {

int month; int day; int year; }; main() {

int index;*point1;*point2; point1=&index; *point1= 11; point2=new int; *point2=22;

cout <<\"The values are \"<cout <<\"The values are \"<delete point1;

float *f_point1,*f_point2;

f_point1 =new float; f_point2=new float; *f_point2=3.14159;

*f_point1=2.4*(*f_point2); delete f_pointl; delete f_point2;

date *d_point=new date; d_point->month=10;

53

《C++面向对象程序设计》 函授自学指导书

d_point->day= 11; d_point->year=2001;

cout<month<< \"/\" <day<< \"/\" <year<< \"\\n\";

delete d_point;

char *c_point;

c_point=new char[30]; delete c_point;

c_point=new char[sizeof(date)+l00]; delete c_point; }

解:根据题意,new和 delete操作符完成指针的动态定位及释放工作。 注意:1)使用new操作符分配的内存必须用delete操作符释放掉,本段程序中point2申请的2字节内存将不会被释放。2)delete操作符只能删除由new操作符申请的内存。故运行结果为: The values are ll 1l 22 The values are l1 88 88 l0/11/2001

例6-7 请在程序段中进行填空,实现进行数据交换的功能。 #incIude void swap(int *p1,int *p2); void main() {

int a,b;

int *pt1,*pt2;

cout<<,'input a,b:\"; cin>>a>>b; pt1=&a; pt2=&b,

swap(ptl,pt2);

cout<<\"result: \"<void swap(int *p1,int *p2) {

int p; p=*p1;

_____①______; _____②______; }

如程序运行时得到以下结果: input a b:6,8 result:8,6

解:swap函数使用两个指针变量作为参数,达到交换两个数据的目的。注意函数参数的传递方式。

正确答案:①*p1=*p2;②*p2=p。

54

《C++面向对象程序设计》 函授自学指导书

例6-8 根据下列程序给出运行结果_。 #include main() {

int i;

char *name[]={ \"Turbo C\cout<<\" 1 .直接方式输出:\\n\"<cout<cout<<\"2. 间接方式输出:\\n\"<cout<< * (name+i)<解:*(name+0)等价于*name,即表示Turbo C,而*(*(name+0)则表示T,*(*(name+0)+2)表示r,*(*name+4)表示。,*(name+3)表示C++Builder,*(*(name+3)+4)表示B,*(*(name+3))表示C,*(*(name+3)+8)表示d。程序运行结果如下: (1)直接方式输出

Turbo C Vlsua1 C++ Borland C++ C++ Builder

(2) 间接方式输出 Turbo C Visual C++ Boriand C++ C++Builder

例6-9 根据下列程序给出运行结果_。 #include main() {

int i;

char *name[ ]={

\"Turbo C\

\"Borland C++\}; char **p;

for(i=0;i<4;i++) {

p=name+I; /* 把name[i]的地址赋给 p*/ cout<<*p<<\"\\n\"; } }

解:本题只要注意指向指针数据的指针变量的定义方法以及存放的值的内容,容易得到以下运行结果: Turbo C Visual++

55

《C++面向对象程序设计》 函授自学指导书

BOflgnd C十个 C++ Builder

例6-10 将下列程序编译成exm6-10时,若执行exm6一10则运行结果为_; 若执行 exm6-10 hello classmates则运行结果为_。 #include

void main(int argc,char *argv[]) {

if (argc= =1) cout<<\"no enough param\\n\"; while(argc-->1)

cout<< * ++ argv< 解:此程序为带参数的主函数,故执行exm6-9 由于无参数,故运行结果为 no enough param;执行exm6-9 hello classmates则运行结果为: Hello

classmates

例 6-11 int*func(int x,int y)的含义是________。 int(*func)(int x,int y)的含义是____________________。

解:前者的含义是声明了一返回值为整型值的指针函数;后者含义是定义了返回值为整型的函数指针。

例6-12 运行下面程序的输出结果为________________。 #include main() {

static float score[] [4]={ { 60,70,80,90 }, { 50,89,67,88 },

{ 34,78,90,66 }, { 80,90, l00,70 } };

float * seek(fIoat(* pointer) [4] ); float *p;int i,j; for(i=0;i<=3;i++) {

p=seek(score+i); if(p= =* (score+i)) {

cout<<\" no.\" <for(j=0;j<4;j++) cout<<*(p+j)<float *seek(float(* pointer) [4] ) {

int i;

float *ptr;

ptr=*(pointer+1); for(i=0;i<=3;i++)

if ((*(*pointer)+i)<60) ptr=*pointer; return(ptr); }

解:根据题意,易知是查找为组中有无低于60的数据及其对应组下标。 运行结果为

56

《C++面向对象程序设计》 函授自学指导书

no 1: 50 89 67 88 no 2: 34 78 90 66 二、选择题

例 6-13 若 p为指针变量,y为变量,则 y=*P++;的含义是_。

A.y=*P; p++ B.y= (*p)++ C.y=p; p++ D.y = *(p++) 解:根据自增运算的规则,对本题应先运算再自增。 正确答案:A。

例6-14 若程序段static chax line[]=\"visual C++\"; char *pointer=line;则pointer的值为_。

A.visualC++ B.line的首地址 C.visual D.\\n

解:根据题意,line为字符数组名,表示首地址;且pointer为指针变量。 正确答案:B。

例6-15 相同数据类型的数组名和指针变量均表示地址;以下不正确的说法是_。

A. 数组名代表的地址值不变,指针变量存放的地址可变

B. 数组名代表的存储空间长度不变,但指针变量指向的存储空间长度可变

C. A和B的说法均正确 D. 没有差别

解:数组在声明的同时就指定了相应的存储空间和存储位置,应认为是 指针常量,而指针变量根据需要可指向任意位置。故只有D的说法不正确。 正确答案;D。 三、编程题

例6-16 求矩阵 a[2][3]={11,22,33,44,55,66}的转置矩阵t[3][2],并按矩阵形式输出两矩阵,要求用指针实现。

解:为了实现本题要求,关键是以指针实现两矩阵中数据传递交换,根据需要可定义两指针int(*P)[3](*q)[2]用以分别指向矩阵a和矩阵b。再根据数组存放的规则,容易得到以下程序: #include main() {

int a[2][3]={ 11,22,33,44,55,66},t[3] [2]; int (*p)[3],(*q)[2],i,j; p=a; q=t;

for(i=0;i<2;i++)

for(j=0;j<3;j++) *(*(q+j)+i)=* (*(P+1)+j);

cout<<\"矩阵A: \"<57

《C++面向对象程序设计》 函授自学指导书

{

for(j=0;j<3;j++)

cout<<*(*p+i)+j)<<\" \"; cout<}

cout<<\"% 矩阵B' \"<for(j=0;j<2;j++)

cout<<*(*(q+i)+j)<<\" \"; cout<【思考题】

一、选择题

1.若int(*p)[5];,则正确的叙述是。。 A..p是指针数组

B.(*p)[5]与*p[5]等价

C. p是指针,它可指向一维数组中任一元素

D.p是指针,它只能指向一个包含5个int类型元素的一维数组

2.现有int b[3][4],*p;p=(int *)b;, 若要指针P指向 b[2][3],以下正确的

是。

A.p+=3*4+3 B.+=2*4+3

C.+=(3*4+3)* sizeof(int) D.+=(2*4+3)* sizeof(int)

3.若 char p,p1[20];*s= \"visual C++\";p 1=P;正确的说法是_。 A.p和 p1的值均为\"visual C++\"

B.第一个赋值语句正确,第二个赋值语句不正确 C.第一个赋值语句不正确,第二个赋值语句正确 D.两个赋值语句均不正确 4.表达式\"A>B\"的值为_。 A.表达式错,不能求值 B.其值\"A>B\"

C.该字符串的首地址 D.不能确定

6.下列说明或赋值语句,不正确的是。 A. static char *ip,ip=\"visual C++\";

B. static char ip1[12]={ 'v','i','s','u','a','l',' ','C','+','+,}; C. static char iP2[12];ip2=\"visual C++\";

D. static char ip3[1=\"visual C++\ 二、填空题

7. 若有以下程序段;则*(*(a+2)+1)的值为______,*(*(p+1)+1)的值

为_____。

static int b[3] [2]={1,3,5,7,9, l 1 };

58

《C++面向对象程序设计》 函授自学指导书

int (*ip)[2]; ip=b;

8. 执行下列程序段后,sa的内容为。

char sa[8],*sb= \"aa\\0bb\\0\"; strcpy(sa,sb);

9. 下列程序的输出结果为_。

#define NULL 0

#include

char *seek(char *string,char c) {

char *p=string;

while(*p&& *p ! =c)p++; return(*p?p:NULL); }

main() {

static char line [] =\" abcdefl 2 3 45 6 7 8 90fghij\"; char n='c ', *q;

q=seek(line,n);q+=4;

for(;*(q+5) !=0;q++) cout.put(*q); }

10.下列程序的输出结果为_。 #include sub(int *x,int i,int n) {

if (n<=i)sub(x,i,3*n);*x+=n++; }

main() {

int x=0;

sub(&x, 12,2);cout<11.下面的函数功能为______。 str1 (char *s) {

int i;

i=strlen(s);

while(*(s+i- l )= =''&&i-->0); *(s+i)='\\0'; }

12.下面的函数功能为__________。 str2(char *s) {

int i,j; i=0;

j=strlen(s);

while(*(s+i) ! =' '&&i++<=j); * (s+i)='\\0';

59

《C++面向对象程序设计》 函授自学指导书

}

13.下面程序的运行结果为_。 #include main() {

static int a[3] [2]={ {12},{ 14,16},{ 1,2} }; int *p=a[1];

cout<<*(p+1)<<\" \"<<*(p+3); }

三、编程题

14.实现将数组a中的数据按逆序存放。要求在主函数中实现数组的定义和排序后的输出,在被调函数中实现排序;用指针完成。

15. 实现对一字符率的空格数进行统计、要求在主函数中确定字符串和统计数据的输出,在被调函数中实现统计,用指针方式完成。进一步思考对所有英文字母进行统计,程序该如何实现。

16. 找出一维数组中最大元素及其下标. 要求主调函数中确定一组数组及输出最大元素和下标值,被调函数中实现查找,用指针实现。

17. 编写两个函数,分别实现两个字符串的比较,用指针实现。 18. 编写可实现字符串的拷贝函数;用指针实现。

第七章 结构体与共用体 【学习要点】

l. 掌握结构体类型说明和结构体类型变量、数组、指针的定义方法。 2. 掌握引用结构体中成员的方法。

3. 掌握给结构体变量、数组赋初值的方法。 4. 掌握结构体成员为指针时的运用。

5. 掌握函数的参数为结构体类型时,参数之间的正确传递。 6. 掌握利用指向结构体的指针成员构成链表的基本算法。

7. 了解共用体、位段结构和枚举类型的说明和变量的定义和赋初值的方法。

8. 理解共用体类型变量中各成员的存储结构,正确引用各成员中的数据。

9. 理解位段结构类型变量中各成员的存储结构。 10.正确引用位段结构类型变量中各成员。

11.正确引用枚举类型常量,了解允许对枚举类型变量进行的操作。

【例题分析】

一、选择题

例7-1 程序中有下面的说明和定义,则会发生的情况是_。

...

60

《C++面向对象程序设计》 函授自学指导书

struct ABC

{ int x; char y; } ...

ABC s 1,s2; ...

A. 编译时错

B. 程序将顺利编译、连接、执行

C. 能顺利通过编译、连接,但不能执行 D. 能顺利通过编译 但连接出错

解:根据结构体类型说明形式要求必须以分号结尾。 正确答案;A。

例7-2 设有以下说明,则正确的赋值表达式为_。 struct a

{int no; char *name; int score; } b;

A.a.no=l23; B.a->no=123; C.b.no=l23; D.b->no=l23;

解:引用结构体变量中成员的方法可通过点操作符和指针运算操作符。考虑变量b不是指针变量以及a为结构体类型。 正确答案:C。

例7-3 以下程序中,fun函数的输出结果是________。 #include struct stu {

int num;

char name [10]; int age; };

void fun (stu *p)

{ cout<<(* p).name; } void main() {

stu student[3]={

{ 980l,\"Zhang\{ 9802,\"Wang\{ 9803,\"Zhao\

};

fun(student+2); }

A.Zhang B.Zhao C..Wang D.18

解:sin结构体类型中的name为包含10个元素的一维字符数组,则name为该数组首地址。在main函数中定义student为成 类型的数组并初始他。student+2 即为&student[2]。

正确答案:B。

例 7-4 设有以下说明,则语句 cout<<(sizeof(struct date)+sizeof(max));

的执行结果是。 typedef union

61

《C++面向对象程序设计》 函授自学指导书

{long i; int k[5]; char c; } DATE;

struct date { int cat; DATE cow; double dog; } too; DATE max;

A.25 B.30 C.l8 D.8

解:cout语句输出的是struct date类型的结构体和变量max所占内存字节数的总和。根据int型变量占2个字节,long int型占4个字节,char型占1个字节,float型占4个字节,double型占8个字节。且C+十中共用体变量所占内存字节数等于其成员中占字节数最多者;而结构体变量则不同,它所占内存字节数是其所有成员所占字节数的总和。DATE是共用体类型,max是该类型的变量。根据DATE类型的共用体中有3个成员:长整型占4个字节,5个元素整型数组占10个字节,字符型占1个字节。取其最大值,故DATE型变量(max和cow)应占10个字节。date类型为结构体,它由3个成员组成:nit型占2个字节,DATE型占10个字节,double型占8个字节。结构体类型变量占2+10+8=20个字节。

正确答案:B。

例 7-5 设有定义语句 enum aa{add,sub,mul, div} opera; ,以下对枚举变量opera的操作中,不正确的是_。

A.opera = (enum aa)2 B. cin>>opera

C.opera = add+1 D.if(opera==sub) cout<<\"OK\";

解:在C/C+十中,枚举元素(枚举值)在内部被处理成一个表示序号的整型常量。例如此例中的枚举元素add的序号为0,sub的序号为1,....但枚举类型不是整型,不可直接将序号值赋给枚举变量,如 opera=2是错误的。可通过强制类型转换再进行赋值,选项 A中的 opera=(enum aa)2;相当于把mul赋给了opera,因此是合法的。

因为各枚举元素都有序号,可对枚举元素进行加(减)一个整数的运算;从而得到其后(前)某个元素,选项C正确,相当于opera=sub;。

枚举类型可以参与关系运算, 参与关系比较的是序号值,选项D 中判别枚举变量opera中的值是否等于枚举常量sub是合法的。

枚举变量不能直接赋整数值,从键盘输入的常量也无法进行强制类型转换,且C/C+十规定枚举变量只能通过赋值语句得到值,不能通过输入得到枚举值。 正确答案:B。 二、填空题

例7-6 设有以下结构类型说明和变量定义 struct stud

{

char num[5]; int s[4]; double ave; } a, *p;

则变量a在内存所占字节数为___①___;变量p在内存所占字节数为___②____。

解:本例中a是一个名为stud结构体类型的变量。该结构体中有三个

成员:一个是字符数组num,它有5个元素,每个元素占一个字节,共占5个字节;第二个成员s是一个整型数组,它含有4个元素,每个元素占两个字节,共占8个字节:第三个成员ave为双精度型,占8个字节。加起来共21个字节。故①为21。

对于变量p,它是一个基类型为stud结构体的指针变量,用于存放stud

62

《C++面向对象程序设计》 函授自学指导书

类型变量的地址,而作为变量的地址(在小系统中)是由16位二进制数表 示的,因而只需两个字节即可存放任一地址值,所以系统将为p分配两个字 节的存储单元,即②为2。

注意:在不同的软件环境下,占用的内存会有所不同。

例7-7 以下程序调用fun函数动态分配两个整型存储单元,并通过形参传口这两个整型存储单元的地址给指针变量s1和s2,请填空。

...

int fun(①) {

*p=new int; *q=new int; }

void main() {

int *s1, *s2; ...

fun(②); ... }

解:由fun函数的定义可知,在fun函数中通过两次使用new操作符来申请两块内存空间,以存放整型数据,并把所分配的存储单元的地址分别存放在*p和*q中,由此可判断出p和q一定是基类型为m型指针的指针变量,因此,①处应填 int**p,int**q。

由于fun函数的形参p和q都是基类型为int型指针的指针,因而在main 函数中调用fun时,实参也必须是两个基类型为int型指针的地址。由于s1 和 s2为int型的指针,因此②处应填&s1,&sZ。

例7-8 假设结构体中的成员按书写顺序从低字节向高字节排列,下 面程序的输出结果是_。 void main() {

unlon vvv {

struct { int x,;char y;} m; char a; int b; } k;

k.a=2; k.b=1;

k.m.x=k.a*k.b; k.m.y=k.a+k.b;

cout<解:本例所定义的共用体变量k包括结构体成员m占3个字节、字符型成员a占1个字节和整型成员b占2个字节。系统按占字节数最多的成员m所需空间为它们分配3个字节。上述3个成员共用存储单元的情况如下所示。

63

《C++面向对象程序设计》 函授自学指导书

执行赋值语句k . a=2;后紧接着又执行了k .b=1的操作,从上图可知:由于成员a和b共用了1字节的存储区,所以这时k .a和k .b的值都是1。

执行k.m.x=k.a*k.b;的赋值操作时,是将1×1的结果存入了同一字节,k .m .x中的值仍为1。

执行 k .m .y=k .a+k .b;的赋值操作时,将 1+l的结果赋给了结构体成员中的字符变量y。

在cout语句中,采用十进制的形式输出k .m .x和k .m .y的值,且两个输出项之间用逗号分隔。

正确答案:1,2。 三、编程题

例7-9 说明一个结构体类型,包含用户的姓名(含6个字符的字符串)和电话号码(含8个字符的字符串)。编写函数用于读入N位用户的数据到结构数组中;编写函数用于将数组中的用户按姓名的字母顺序重新排列;编写函数用于输出数据。

解:按题目要求,需说明包含姓名及电话号码两个成员的一用户类型struct USER,由于字符串总以'\0'为结束标志,因而应定义合适的数组长度以便存放字符串结束标志。具体的定义:struct USER{char name[7];chartel[9];}。

main()函数中需定义一个结构体数组user,用于存放N位用户的数据(用户姓名、电话号码),此处N是常量。函数getUser用于读取N位用户的数据并存人user数组中;函数sortUser用于将user数组中的N位用户按其姓名的字母顺序重新排列:函数outUser用于将重新排序后的user数组输出。完整程序如下: #include #include struct USER {

char name[7]; char tel[9]; };

void getUser(USER *p, int n) {

int i;

cout<<\"please input all users' name and tel\"<cin>>p[i]fname >>p[i].tel; }

void sortUser(USER *p, int n) {

64

《C++面向对象程序设计》 函授自学指导书

int i,j,k; USER temp;

for(j=0;jk=j;

for( i=j+1;iif(strcmp(p[i].name,p[k].name )<0) k=i; if(k!=j) {

temp=p [k]; p[k]=pU]; p[j]=temp; }

} }

void outUser(USER *p, int n) {

int i;

cout<cout<void main() {

const int N=5; USER user[N]; getUser(user,N); sortUser(user,N); outUser(user,N); }

例7-10 约瑟夫问题。设有n个人坐在圆桌周围,从第s个人开始报数,报到m的人出列,然后再从下一个人开始报数,数到m的人又出列,....,如此重复,直到所有的人都出列为止。要求按出列的先后输出每一个人的信息。

解;设圆桌周围的n个人的信息构成一个带表头结点的单链表。先找到

第s个人对应的结点;从此结点开始,顺序扫描m个结点,将扫描到的第m个结点删除,然后重复上述动作,直工输出n个结点。程序如下:

#inc1ude struct Node {

int personID; Node * next; };

Node * CreateList(int n) //创建带表头结点的单链表 {

int i;

Node *head, *p, *q; if(n==0) return NULL;

65

《C++面向对象程序设计》 函授自学指导书

head=new Node; q=head;

for(i=0;ip=new Node;

p->personID =i+1; q->next =p; q=P;

}

p->next =NULL; return head; }

void Joseph(int n, int s, int m) {

int i,j;

Node * CreateList(int n); if(nNode *h, *p, *q, *r ;

h=CreateList(n); //创建链表 q=h;

for(i=l;inext;

for(i=1;ifor(j=l ; jif(p->next !=NULL && q-->next !=NULL) {

q=q->next; p=p->next; }

else if(p-->next = =NULL) {

q=q->next; p=h->next; } else {

q=h->next; p=p->next; }

cout<personID <<\"\"; //一个元素出列 r=p;

if(p->next ==NULL) {

p=h->next;

q->next =NULL; }

66

《C++面向对象程序设计》 函授自学指导书

else {

p=p->next;

if(q->next !=NULL) q->next =p; else h->next =p; }

delete r ;

}

cout<next ->PersonID <void main() {

Joseph(10, 1,3); }

【思考题】

一、选择题

1. 以下程序的输出是_。

#include void main() {

struct cmplx {

int x; int y;

} cnum[2]={ 1,3,2,7 };

cout<A.0 B.0 C. 3. D. 6

2. 以下结构体说明和变量定义中,正确的是_。 A.struct abc { int n; float m }; B.struct ABC{ int n; float m; } struct ABC x,y;

C.typedef struct abc{int n; float m; } ABC; ABC x,y; D.struct abc{ int n; float m;}; abc x,y;

3. 结构体成员在内存中从高位到低位的排例顺序为_。

A. 按结构体说明中成员出现的先后顺序,先出现的在低位 B. 按结构体说明中成员出现的先后顺序,先出现的在高位 C. 占内存量少的成员在低位 D. 占内存量大的成员在低位 4. 已知教师记录描述为 struct teacher {

int id;

char name[20]; struct {

int y; int m; int d; } birth;

67

《C++面向对象程序设计》 函授自学指导书

}t;

将变量t中的d成员赋值为12的语句为:

A.d=12 B.birth .d=12 C.t .d=l2 D.t .birth.d=l2 5.设有以下说明语句 struct ex {

int x; float y; char z; }example;

则下面的叙述中不正确的是:

A .struct是结构体类型的关键字

B.example是用户定义的结构体类型名 C.x,y,z都是结构体成员名 D. ex是用户定义的结构体类型 6.设有如下定义 sttuct st {

int id; float score; } stdl, *p ;

若要使P指向stdl中的id域,正确的赋值语句是 A.p=&std1.id; B.p=(struct st*) stdl.id; C.p=(struct st*) &std1.id, D.*p=std1.id; 7.有右图结构体说明和变 量的定义,p指向变量a,q指 向变量b。下面不能把结点b连 接到结点a 之后的语句 是________。

A.a .next= q; B.p .next= &b; C.p->next=&b; D.(*p) .next= q;

8在定义一个共用体变量时,系统为其分配存储空间的原则是_。 A. 按所有成员需要的存储空间总和分配 B. 按成员中占存储空间最大者分配

C. 按成员中占存储空问最小者分配 D. 按第一个成员所需的存储空间分配 9.下例程序的输出结果是_。

#include void main() //假定此处int占 2字节,long为 4字节 {

union {

int i[2]; long k; char c[4]; } *s, a;

s=&a; s->i[0]=0x39; s->i[i]=0x38; cout<k<A.3839 B.3938 C.380039 D.390038

10.设有以下枚举类型定义;枚举量 Fortran的值为____。 enum language {Basic=3, AssembIy, Ada=100, colol, Fortran};

68

《C++面向对象程序设计》 函授自学指导书

A.1 B. 6 C.102 D.103 二、填空题

11. 以下min函数的功能是:在带头结点的单向链表中查找结点数据域 为最小的值;并作为函数返回值。链表结构如下图示,请填空。

struct NODE

{ int data; NODE * next;};

int min(NODE * first) {

NODE *p; int m;

p=first->next; m=p->data;

for(p=p->next; p!=NULL; p=_____)

if(m>_____ ) m=p->data; return m; }

12. 假设int变量在内存中占2个字节,若有如下定义、说明和语句, 请回答问题.

struct aa {int i, char c;}; struct st{

int a[6]; struct aa c; } w[3], *pw; pw=w ;

(1)数组W在内存中所占的字节数是_。

(2)通过数组w中第0个元素引用结构成员a[3]的形式是_。 (3)通过数组w中第0个元素引用aa结构的c成员的形式是_。

(4)通过指针变量pw引用w第0个元素中a[3]的全部可能的形式是_。

(5)通过指针变量 pw引用 w中第 1个元素 aa结构中 c成员的全部可

能的形式是_。

13.已知 head指向一个带头结点的链表;链表中每个结点包含整型数据域data和指向链表结点的指针域next,以下函数返回链表中所有结点数据域的和,请填空。 struct list

{ int data; list *next, }; void main() {

struct list *head; int s;

s=sum(head); ......

69

《C++面向对象程序设计》 函授自学指导书

}

int sum(_________) {

struct list *p; int s=0; p=p->next;

while(p ! =NULL)

{ s=_________; p=_________;} return s; }

14. 以下程序的输出结果是_。 #include void main() {

enum team{ qiaut, cubs=4, pick, dodger=qiaut-2};

cout<15. 以下程序的输出结果是.. #include void main() {

enum aa{ Sat=5, Sun };

char *w[]={ \"Sun\cout<三、编程题

16. 已知 head指向一个带头结点的单向链表,链表中每个结点包含数 据域data与指针域next,数据域为整型。请分别编写函数,在链表中查找 数据域最大的结点.

(l)由函数值返回找到的最大值。

(2)由函数值返回最大值所在结点的地址值,在主函数中通过地址输 出该结点数据域。

(3)由参数传回找到的最大值。

(4)由参数传回最大值所在结点的地址值,在主函数中通过地址输出 该结点数据域。

第八章 类与对象 【学习要点】

1. 掌握类与对象的概念和定义方法,构造函数和析构函数的特性与定义。 2. 掌握一成员的访问属性。 3. 掌握对象的创建过程。

4. 掌握构造函数的概念、定义方法和使用方法。

70

《C++面向对象程序设计》 函授自学指导书

5. 掌握析构函数的概念、定义方法和使用方法。 6. 掌握构造函数对类成员进行M始化的方法。

7. 掌握拷贝构造函数的概念、定义方法和使用方法。 8. 掌握包含对象成员的类的构造函数的定义方法。

9. 注意与 malloc和 free的不同、malloc和 free用于内存的分配和回收,无

法创建类对象;而new和delete不仅分配和释放堆空间,而且new能自动调用构造函数创建了相应的类对象;delete 自动调用析构函数删除类叶象。

10.掌握静态成员的概念、定义方法、作用和特点。 11.掌握友元的概念、定义方法、作用和特点。

【例题分析】

例8-1 指出下面各程序段中的错误。

(1 ) class A {

int i=1; int j=l; ... }

解:在类定义时,要注意:1)不允许初始化数据成员:2)结束类定义需用分号。故本题错误有两处。 (2 ) #include class Time {

public:

int hour, minute, second; void printTime(); void setHour(int h); ... };

void printTime() {

cout<<\"\\nhour:\"<void setHour(int h) {

hour=h; }; ...

void main() {

Time aTime;

aTime setHour(5); aTime printTime(); … }

解:在成员函数的定义和引用时要注意:1)成员函数定义时应加“类

71

《C++面向对象程序设计》 函授自学指导书

名::”;2)函数定义结束时在}后不必加“;”,这与类定义不同;3)成员函

数引用时应在对象名和成员函数名之间加“.”。故本题错误有三处。 例8-2 下列程序的运行结果是_。 #include class Tpoint {

public:

Tpoint(int x,int y) { X=x ;Y=y ; cout<< \"Constructor Called.\" << endl ; } TPoint(const TPoint &p);

~Tpoint() {cout<<\"Destructor Called.\\n\";} int Xcord() {return X; } int Ycord() { return Y ;}

private:

int X,Y; };

Tpoint::Tpoint(const Tpoint &p) {

X=p .X; Y= p.Y;

cout<<\" Copy_initialization Constructor Called.\\n\"; }

Tpoint move(Tpoint q) {

cout<<\"ok\\n\"; int x,y;

x=q .Xcord()+10; y=q .Ycord()+20, TPoint r(x,y); return r ; }

void main() {

Tpoint m(15,40),P(0,0); Tpoint n(m); p=move(n);

cout<< \"p=\" <

解:根据构造函数和拷贝构造函数的特点,执行该程序后,输出结果是: Constructor Called. Constructor Called.

Copy initialzation Constructor Called. Copy initialzation Constructor Called. ok

Constructor Called.

Copy initialzation Constructor Called.

72

《C++面向对象程序设计》 函授自学指导书

DestIuctor Called. Destructor Called. Destructor Called. p=25,60

Destructor Called. Destructor Called. Destructor Called. 说明:

(1)构造函数执行三次,分别初始化主已数中的对象m,p和move函 数中的对象r。

(2)拷贝构造函数共执行了三次。第一次,初始化对象n;第二次在调 用函数move()时,实参n给形参q进行初始化;第三次是执行函数move的 return r;语句时,系统用 r初始化一个匿名对象时使用了拷贝构造函数。

(3)析构函数执行了六次。在退出函数move时释放对象r和q共调 用二次;返回主函数后,匿名对象赋值给对象p后,释放匿名对象又调用一 次析构函数;最后退出整个程序时释放对象m对和p调用三次。

例8-3 指出下列程序中的错误。 #include class person {

public :

person(int n);

person(int n,char * m, char * d); private: int no;

char name[20]; char add[40]; };

person:: f fperson(int n) {

no=n;

strncpy (name, \"jenny\strncpy(add, \"office\}

person::person(int n,char * m= \"no name\ {

no=n;

strncpy (name, m, s izeof(m)); strncpy (add,d, sizeof(d) ); }

void main() {

Person apersonl; Person aperson2(2); }

解:1)若类定义中含有自定义构造函数,则编译程序不会自动生成缺

73

《C++面向对象程序设计》 函授自学指导书

省构造函数;所以声明语句Person apersonl;不正确,对象名 apersonl后 应带参数。2)创建类对象时,重载构造函数的参数匹配,尤应注意,特别 是在有默认参数情况下,创建对象apersonZ时调用构造函数出现了二义性。 应对重载函数的参数和对象创建时的参数进行适当调整。 例8-4 根据下列程序写出运行结果。

#include class Exm {

public:

void Setij(int a,int b){i=a;j=b;} ~Exm) {

cout<<\"p[\"<int GetPlus() {return i+j; } protected:

int i; int j; };

void main() {

Exm* p;

p=new Exm[10]; if(!P) {

cout<<\"allocation ermr\\n\"; return; }

for(int j=0;j<10;j++)

p[ j ].Setij(j, j );

for(int k=0;k<10;k++)

cout<解:运行结果: 0+0=0 1 +l =2 2+2=4 3+3=6 4+4=8 5+5=10 6+6=12 7+7=14 8+8=l 6 9+9=18

P[l] has been destroyed P[2] has been destroyed P[3] has been destroyed

74

《C++面向对象程序设计》 函授自学指导书

P[4] has been destroyed P[5] has been destroyed P[6] has been destroyed P[7] has been destroyed P[8] has been destroyed P[9] has been destroved

例8-5 根据静态成员的特点,指出下列程序的错误。 #include #include class Part {

public:

Part(char* pname=\"no name\") {

strcpy(name,pname); noofPaxt++; no=noofpart;

cout<<\"creat the no: \"<~Part() {

noofPart--;

cout<<\"desttoy the no: \"<static int number(){ return no;}

protected:

static int noofPed=0; int no;

char name[40]; };

void main() {

Part p1; Part p2; }

解:1)静态数据成员不能在类说明中分配空间和初始化,所以类声明 中只能对静态成员进行引用性声明:static nit noofpart;在类声明外文件作 用域的某个地方定义性声明:int Part::noofpart = 0 ;。2)静态成员函数只能 访问静态数据成员,所以静态成员函数 numbe中return no;不正确,改成 returnnoofpart。

例8-6 计算两点之间的距离。

方法1:定义点类(Point),再定义一个类(Distance)描述两点之间的 距离,其数据成员为两个点类对象,两点之间距离的计算由构造函数实现。

#include #include class Point

75

《C++面向对象程序设计》 函授自学指导书

{

public:

Point(int a=0,int b=0){ x=a; y=b;} int xcord() { return x; } int ycord() { return y; } private: int x,y; };

class Distance {

public:

Distance(Point q1,Point q2); double getdist(){ return dist; } private:

Point p1,p2; doub1e dist; };

Distance::Distance(Point ql,Point q2):p 1 (q 1 ),P2(q2) {

double x=double(pl .xcord()--P2.xcord()); double y=double(p1 .ycord()--P2.ycord()); dist=sqrt(x*x+y *y); }

void main() {

Point p(0,0),q(1,1); Distance dis(p,q);

cout<<\"The distance is: \"<方法2:将求两点间距离的函数声明为Point类的友元函数。 #include #inc1ude class Point

{ ... //与上面定义同,此处省略。

friend double Distance(Point p1,Point p2); };

double Distance(Point p1,Point p2) {

double dx=double(p1.x-P2.x); double dy=double(p1.y-P2.y); return sqrt(dx*dx+dy*dy); }

void main() {

Point q1(0,0),q2(1,1);

cout<<\"The distance is: \"<76

《C++面向对象程序设计》 函授自学指导书

【思考题】

一、定义类

1. 定义计数器类Counter。要求具有以下成员:计数器值;可进行增值 计数;可进行减值计数;可提供计数值。

2. 定义日期类 Date。要求具有以下成员:可设置日期;可进行加1操 作;可输出“日/月/年”格式的日期。

3. 定义盒子Box 类。要求具有以下成员:可设置盒子形状;可提供盒 子体积;可提供盒子表面积。

4. 定义一个 string 类表示字符串,其数据成员为字符型指针变量,成 员函数包括构造函数、拷贝构造函数、析构函数和一个用于显示字符串的函数。

5. 定义一个 Person 类,数据成员包括姓名、年龄、性别、地址,其中 姓名、地址为 string 类对象。成员函数包括构造函数、析构函数和一个显示 所有数据成员值的函数。

6.设计一货物类,每箱货物是这个类的对象,每箱货物都有重量,且 不一定相同。分别用构造函数和析构函数模拟货物的购进和卖出,用静态数 据成员来记录目前库存货物的总重,还要有能获得货物重量和目前库存货物 总重的成员函数。

7.定义一个Car类和Tuck类,用友元实现两类对象行使速度的快慢 比较。

二、指出并改正以下程序中的错误。 8.#include #include class Point {

public:

void set(double ix, double iy) {

x=ix; y=iy; }

void xOffset(); void yOffset(); void angle(); void radius() protected: double x; double y; }

void set(double ix, double iy) {

x=ix; y=iy; }

77

《C++面向对象程序设计》 函授自学指导书

void xOffset() {

return x; }

void yOffset() {

return y; }

void angle() {

return (180/3.14159)*atan2(y,x); }

void radius() {

return sqrt(x*x+y*y); }

void main() {

Point p; double x,y;

cout <<'Enter x and y:\\n\"; cin>> x>>y, poset(x,y); p->x+=5; P->y+=6;

cout <<\"angle=\"<<<\<<\

<<\}

三、编程题

9.将第8题改正后的程序分离成类定义和主函数,成为多文件结构。主函数采取包含类定义的头文件的方法。写出运行结果。

四、判断并说明理由

10.类描述的是一类事物所应具有的共同属性,而对象是类的一个确定事物的具体属性。

11.对主函数中未用到的成员函数,在类定义中不应出现。

12.对类Time而言,其成员函数set(int hour,int minute,int second)的全 名应为::set(int hour,int minute,int second)。

13.成员函数的定义不能放在类定义的头文件中,因其不是内联函数。 14.成员函数的定义与类定义分开是通常的做法,可以将类定义的头文件 看成是类的外部接口,类的成员函数定义看成是内部实现,方便程序的开发。 15.进行成员函数定义时,类名可以加在成员函数名之前也可以加在该 函数的返回类型前。

78

《C++面向对象程序设计》 函授自学指导书

16.只要成员函数名相同即认为是成员函数的重栽。

17.类的封装性体现在部分数据被说明为保护时,它们只允许内部访问, 而禁止外界访问,从而防止外界的干扰和误操作。 18.析构函数可以有一个或多个参数。 19.构造函数和析构函数都不能重载。 20.另一个类的对象可以作为该类的成员。 21.通常拷贝构造函数的参数是该类的对象。 五、写出下列程序的输出结果。

22. #include class test {

public: test(); test(int); ~test();

void display(); protected: int n; };

test::test() { cout<<\"Constructing normally\\n\"; } test::test(int num) { n=num;

cout<<\"Constructing with a number\"'<void test::display() {cout<<\"Display a number: \"<test:: ~test() {cout<<\" Destructing\" <void main() {

test obj1; test obj2(59); obj1.display(); obj2.display(); }

23.#include class Count {

public:

Count(){count++; }

static int getn() {return count; } ~Count(){ count--; } private:

static int count; };

int Count::count=100;

79

《C++面向对象程序设计》 函授自学指导书

void main() {

Count c1,c2,c3,c4;

cout<第九章 继承与派生类 【学习要点】

l. 掌握继承和派生的概念;派生类的定义方法.

(1)掌握private,public,protected三种继承方式的特点。继承方式决定了

基类中的成员在派生类中的访问属性。三种继承方式的共同点:基类的private 成员在派生类中不可见。区别:对于私有继承,基类的public,protected成员 在派生类中作为private成员;对于公有继承,基类的public,protected成员在 派生类中访问属性不变:对于保护继承,基类的public成员在派生类中作为 protected成员,基类的protected成员在派生类中作为private成员。

(2)掌握派生类中的构造函数和析构函数的使用。基类的构造函数和 析构函数不能继承,所以必要时在派生类中需定义自己的构造函数和析构函 数。派生类的构造函数完成基类中新增数据成员和基类数据成员的初始化, 基类数据成员的初始化通过调用基类构造函数来实现。 (3)掌握派生类的同名覆盖规则。

(4)掌握赋值兼容规则。基类对象可以使用公有派生类对象来代替, 包括:派生类对象可以赋值给基类对象;派生类对象可以初始化基类对象的 引用;基类类型指针可以指向派生类对象。

2. 掌握多重继承的概念、定义方法、多重继承派生类构造函数的执行 顺序。派生类构造函数的执行顺序是先执行所有基类的构造函数(顺序按照 定义派生类时指定的各基类顺序),再执行对象成员所在类的构造函数(顺序 按照它们在类中的声明顺序),最后执行派生类构造函数体中的内容。

3.掌握虚基类的概念和定义.在多重继承中,如果多条继承路径上有一 个公共的基类,则在这些路径的汇合点上的派生类会产生来自不同路径的公 共基类的多个拷贝,如果用virtual把公共基类定义成虚基类测只会保留公共 基类的一个拷贝。

【例题分析】

例9-1 指出并改正下面程序中的错误。

#include class Point {

public:

Point(int a=0,int b=0) {x=a,y=b;}

80

《C++面向对象程序设计》 函授自学指导书

void move(int xoffset,int yoffset) { x+=xoffset;y+=yoffset;} int getx() {return x; } int gety() {return y; } private: int x,y;

};

class Rectangle:privatC Point {

public:

Rectangle(int x,int y,int l,int w):Point(x,y) {

length=l; width=w; }

int getlength() {return length; } int getwidth() (return width; ) private:

int length,width; };

void main() {

Rectangle r(0,0,8,4); r.move(23,56);

cout<解:私有继承方式使基类中的public成员在派生类中的访问属性变为private,所以派生类 Rectangle的对象 r不能直接访问基类的成员函数move(),getx()和gety()。其改正方法有两种:1)将Rectangle的继承方式改为公有继承public;2)在Rectangle类中重新定义move(),getx()和罗ty()函数,覆盖基类中的同名函数。

void Rectangle::move(int xoffset,int yoffset) {Point::move(xoffset,yoffset); } void Rectangle::getx() { return Point::getx(); } void Rectangle::gety() { return Point::gety(); } 例9-2 分析下面程序的运行结果。 #include class Base {

public.

void display(){ cout<<\"Base::display()\"<class Derived:public Base {

public:

void display() {cout<<\"Derived::fdisplay()\"<81

《C++面向对象程序设计》 函授自学指导书

void main() {

Derived d;

Derived *pd=&d; Base *pb=&d; pd->display(); pb->display(); }

解;运行结果: Derived:: display() Base::display()

说明:基类类型的指针指向派生类对象时,只能访问从基类继承的成

员。

例9-3 定义一个圆柱体类,该类可实现求圆柱体体积,它继承了圆类 和高类。圆类可以求圆面积,能描述圆心和半径。 解:

class Circle {

float x,y,r ; public:

Circle(float a,float b,float c) {x=a;y=b;r=c; } float getx() {return x; } float gety() {return y; } float getr() {return r; }

float area() {float a;a=r*r*3.14159; return a; } };

class High {

float high; public:

High(float h) {high=h; } float geth() {return high;} };

class Cylinder:pubIic Circle,private High {

public:

float volumn;

Cylinder(float a,float b,float c,float d):Circle(a,b,c),High(d) {

volumn=area() * geth(); }

float getvolumn() { return vo1umn; } };

例9-4 指出并改正下面程序中的错误。 nincIude

82

《C++面向对象程序设计》 函授自学指导书

class A {

public: int x;

A(int a=0) { x=a; }

void display() { cout< <\"A.x\"=\" <class B {

public: int x;

B (int a=0) {x=a; }

void display(){cout<<\"B.x=\"<class C:public A,public B {

int y; public:

C(int a,int b,int c).A(a),B(b) {

y=c; }

int gety() { return y; } };

void main() {

C myc(1,2,3); myc.x=10; myc.display(); }

解:类A,B中有同名公有数据成员x和同名公有成员函数disPlay(),在主函数中访问对象myc的数据成员x时无法确定是访问从A中继承的x还是从B 中继承的X;调用成员函数也是如此,无法确定是调用类A中的还是类B 中的,产生二义性。改正方法,可以用作用域区分符加以限定,如改成myc.A::x=10; myc.A::display();或myc.B::x=10; myc.B::display(); 例9-5 分析下列程序的运行结果。

#include class A {

pub1ic:

A(const char *s) {cout<};

83

《C++面向对象程序设计》 函授自学指导书

class B:virtual public A {

public:

B(const char *s1,const char *s2):A(s1) {

cout<class C:virtual public A {

public:

C(const char *s1,const char *s2) :A(s1 ) {

cout<class D:public B,public C {

public:

D(const char *s1,const char *s2,const char *s3,const char *s4) 'B(s1,s2),C(s1,s3),A(s1) {

cout<< s4<void main() {

D *p=new D(\"class A\delete p; }

解;该程序的执行结果为: class A class B class C c1ass D

说明:创建D对象时,只有在D的构造函数的初始化列表中列出的虚基类构造函数被调用,D的两个基类B,C的构造函数中的虚基类构造函数被忽略,不执行,从而保证在D对象中只有一个虚基类于对象。

【思考题】

一、改错题

l.指出下列程序的错误并改正。

#include

84

《C++面向对象程序设计》 函授自学指导书

class employee {

int age; float salary;

friend void fun(); protected: char *name; public:

employee(char *nm,int ag,f'loat salr); void print() { }; ~employee(); };

class manger:public employee {

char *department; public:

manger(char *nm,int ag,float salr,char *dep); void print(); };

void manger::print() {

cout<< \" name :\" <void fun() {

cout<<\"department: \"<提示:友元函数不能继承。 二、判断题

2. 派生类是基类的子集。

3. 派生类构造函数的初始化列表中不能包含基类对象成员的初始化。 4. 在保护继承中,基类中的所有成员对派生类对象都是不可见的。 5. 在公有继承中,基类中的公有和私有成员在派生类中是可见的。

6. 多继承情况下,派生类构造函数调用基类构造函数的顺序取决于派生类构造函数初始化列表中的基类)顺序。

7. 基类和派生类中同时出现同名函数会存在二义性问题。

8. 一个派生类的两个基类中有同名成员,在派生类中对这个成员的访问可能出现二义性。 三、程序填空

9.下面程序的输出结果是_。

#include class A {

public:

85

《C++面向对象程序设计》 函授自学指导书

A(int a1,int a2) { count1=a1, count2=a2; } int inc1() {return ++count1; } int inc2() {return ++count2; }

void show() (cout<<\"count1 =\"<private:

int count1,count2;

};

class B:private A {

public:

B(int a1,int a2,int a3):A(a1,a2),count3(a3) { } int inc1() { return A::inc1(); } int inc2() (return ++count3; ) void show() {

A::show();

cout<<\"count3 =\" <class C:public A {

public:

C(int a1,int a2,int a4):A(a1,a2),count4(a4){ } int inc1() {

A::inc1(); A::inc2();

return A::inc1(); }

int inc4(){ return ++count4; } void show() {

A::show();

cout<< \"count4=\" <} private:

int count4; }:

class BC:private B,public C {

86

《C++面向对象程序设计》 函授自学指导书

public:

BC(int al1,int a12,int a13,int a21,int a22,int a23,int a): B(a11,a12,a13), C(a21,a22,a23) {

count5=a; }

int inc1() {

C::inc 1 ();

return C::inc l (); }

int inc5() {return ++count5; } void show() {

cout<< \"C.. show()\"<cout<<\" count5 =\" <int count5; };

void main() {

BC my(1,2,3,4,5,6,7); my.show(); cout<my.inc1(); my.inc4(); my.inc5(); my.C::inc1(); my.show(); }

10.在下面程序的划线处填空。 #include #include class University {

char uniname[50]; //校名 long stnum; //学生人数 public:

University(char *p=\" \{

strcpy(uniname,p); stnum=num; }

___________________________

{

strcpy (uniname,x .uniname); stnum=x.stnum; }

void print();

87

《C++面向对象程序设计》 函授自学指导书

};

class Department:public University {

char depname[50]; int depnum; public:

Department(char *uni=\" \:____________________________________

Department(University &x,char *dep=\" \_____________________________________ void print(); };

void University::print() {

cout<<\"校名: \"<cout<<\"全校学生人数: \"<void Department::print() {

University::print()

cout<<\"系名: \"<cout<<\"全系学生人数不: \"<四、编程题

11.定义描述学生类和教师类,并实现测试和简单的输入输出。学生和教师均有姓名、性别、出生年月,这可定义成一个基类,由基类派生学生和教师类,学生类增加班级、学号、学期成绩总分,教师类增加教研室(或部门)、职称、工资。

12.以下是大学人员的类层次结构,根据你的理解给出各类定义,并写出测试程序。

88

《C++面向对象程序设计》 函授自学指导书

第十章 运算符重载与虚函数 【学习要点】

1.理解多态性与虚函数的概念和作用。在C++中,编译时的多态性是由重载函数和运算符支持的;运行时的多态性则是通过使用继承和虚函数实现的。需要注意的是,只有在通过基类指针存取时,才能获得运行时的多态性。

2.理解运算提重载的意义和作用、在C++中,用户可根据需要对运算符赋子多种意义,以配合用户自定义的数据类型,运算符重载是通过创建运算符函数operator()来实现的。

3.掌握成员运算符函数的实现方法。大多数C++系统预定义的运算符能被重载,但运算符(结构成分选择符)、. *(结构指针间接引用符)、::(作用域分辨符)、?:(条件三元运算符)、sizeof、#及# #(预处理符)是不能被重载的。

4.掌握友元运算符函数的实现方法。友元运算符函数与成员运算符函数不同,它不属于任何类对象,没有m 指针。使用友元函数重载时请注意,运算符=、()、[ ]、 ->是不能用友元函数重栽的。

5.掌握虚函数与继承的关系、虚函数定义和实现方法。 6.掌握纯虚函数的定义及实现方法。

【例题分析】

一、改错题

例10-1 阅读如下程序段,指出其中的错误。

class base { private: int n; public:

virtual base(int m):n(m) { } virtual void shown() {

cout<<\"l.n is: \"<class derived:public base { private: char ch; public:

derived(int dn,char dch):base(dn) {

ch=dch; }

void shown() {

89

《C++面向对象程序设计》 函授自学指导书

cout<<\"2.n:\" <}

解:本段程序有两个错误。第一个错误virtual base(int m):n(m),构造函数不能声明为虚函数,因为要正确地生成对象,必须知道确切的函数类型,但需注意的是,析构函数可以声明为虚函数。第二个错误是继承类derived的shown()函数不能使用基类base的私有数据成员n,为此可将base中n的属性定义为protected。

例10-2 阅读如下程序,指出其中的错误。

#include class cl {

int x,y; public: c1() { }

cl(int x1, int y1):x(x1),y(y1){ } cl operator @(cl o) { cl temp,

temP.x=x+o.x; temP.y=y+o.y; return temp; }

int operator #(c1o) {

return (x*y);

}

friend c1 operator =(cl o) {

x=o.x; y=o.y; return *this }

void show(){

cout<<\"x=\"<main() {

c1 a(2,3), b(2,3),c; (a+b).show(); c=a;

c.show(); }

解:本段程序有三处错误:第一处是c1 operator@(cl o),运算符重载是允许用户重新定义运算符含义,但此运算符必须是C++系统预定义的,而@不是 C+十系统预定义的运算符。第一处错误是operator #(cl o),符号#不允许重载。只需将@和#换为其他运算符即可,如“+”、“*”等。第三处是函数friend c1 operator=(c1 o),此部分有二个错误,首先,赋值运算符“=”应定义为类的成员函数,而不能定义为友元函数:其次,友元函数没有this指针,故将friend删去即可。

90

《C++面向对象程序设计》 函授自学指导书

例10-3 运行下面程序,其输出结果为:

Show a: This is a string. Show b: ≠△〥

显然,b的输出结果错的,试找出原因并改正。

#include #include #include class Msg {

char *pstr; public:

Msg() { pstr=new char(NULL); } Msg(char *s) {

pstr=new char[strlen(s)+1]; strcpy(pstr,s); }

~Msg() { delete []pstr;} //析构函数 void show(){ cout<void func(Msg &o) {

Msg a(\"This is a string.\"); cout<<\"Show a:\"; a.show(); o=a; }

main() {

Msg b, func(b);

cout<<\"Show b: \"; b.show( ); }

解:问题出在func(MSg &o)函数的赋值语句o=a。类中若没有重载赋值运算符,C++则以缺省方式进行赋值,即将源对象逐个拷贝到目标对象冲。函数func(Msg&o)在调用过程中,对象a向对象b的引用赋值,使a和b各自的指针pstr指向了同一存储区域,当程序从函数返回时,析构函数D~Msg()被系统自动调用,对象a撤消,a的指针pstr所指向的区域被释放,这使b的指针pstr指向了难以预料的数据。为此,应定义赋值运算符成员函数.使a和b有各自的字符串存储区域,可增加如下程序段: Msg &Msg::operator =(Msg &s) {

if(this= =&s) return *this; //避免向自己赋值 delete pstr;

pstr=new char[strlen(s.pstr)+1]; //重新分配区域 if(!pstr) {

91

《C++面向对象程序设计》 函授自学指导书

cout<<\"Allocation Error !\\n\"; exit(1 ); }

strcpy(pstr,s.pstr); return *this;

}

二、填空题

例10-4 下面程序的运行结果是_ #include const double PI=3. 14l59; class Point { private: int x, y; public:

Point(int sx,int sy):x(sx),y(sy) { }.

double circumference() {

return (0.0); } };

class Circle:public Point { private: int radius; public:

Circle(int x,int y,int rad): Point(x,y), radius (rad) { }

double circumference() {

return (2.0*PI*radius); } };

void main() {

Point *p=new Point(30,30); Circle *c=new Circle(10,10,40);

cout<<\"周长是: \"<circumference() <c ircumference ()<解:这是一个在基类和派生类中函数重载的例子。程序中的circumference()函数的用法完全相同,只是属于不同类。p一> circumference()执行基类Point中的circumference()函数,c一>circumference()执行派生类Circle中的circumference()函数。故运行结果是:

92

《C++面向对象程序设计》 函授自学指导书

周长是:0

周长是:251.327 三、编程题

例10-5 若向量a在三条坐标轴上的投影为ax,ay,az,则表达式a={ax,ay,az}称为向量a的坐标表达式。设有两个向量a和b,它们之间的加、减。数量积的运算规则为:

a+b = { ax + bx, ayy+by+,az+bz } a-b = {ax - bx, ay-by+,az-bz} a*b = ax* bx + ay * by + az * bz

将操作符“+”、“一”、“*”和“=”重载,实现向量间的加、减、数量积和赋值运算。

解:根据题意,若采用结构类型来定义向量,结合相应函数实现向量间的加、减、数量积和赋值操作不难实现题目要求,但若采用操作符重载则更加直观、方便。

#include #include

class Vector { // 定义类 private:

float x,y,z; public:

Vector(fioat vx=0,float vy=0,float vz=0) { // 构造函数 x=vx; y=vy; z=vz; }

Vector(float *a) { // 构造函数 x=* a; y=*(a+ 1 ); z=*(a+2); }

Vector operator=(Vector v); Vector operator=(float a[3]);

friend Vector operator+(Vector v1, Vector v2); friend Vector operator (Vector v1, Vector v2); friend float operator*(Vector v1, Vector v2);

void show() {

cout<Vector Vector::operator=(float a[3]) {

x=a[0]; y=a[1]; z=a[2]; return *this; }

93

《C++面向对象程序设计》 函授自学指导书

Vector Vector::operator=(Vector v) {

x=V.x; y=v.y; Z=v.z;

return *this; }

Vector operator+(Vector v1,Vector v2) {

Vector temP;

temP.x=v1.x+v2.x ; temP.y=v1.y+v2.y ; temP.z=vl.z+v2.z ; return temp; }

Vector operator (Vector v1,Vector v2) {

Vector temp;

temP.x=v 1 .x-v2 .x ; temp.y=v 1 .y-v2 .y ; temp.z=v 1 .z-v2 .z ; return temP ; }

float operator*(Vector v1, Vector v2) {

return(v1.x*v2.x+v1.y*v2.y+v1.z*v2.z);

}

void main() {

float a[]={1.0,2.0,3.0 };

Vector v1(a),v2(l.0,2.0,3.0),v3; v3=v1+v2; v3. show();

cout<<\"v1*v2= \"<说明:程序中 show()函数使用了库函数 double fabs(double x),其作用是求x的绝对值,函数fabs(double x)的原型说明在math.h中。snow()函数之所以如此编写是为了使向量数据输出形式规范。该程序采用了友元函数形式重载“+”、“一”、“*”运算符,在此亦可对成员函数重载,从程序可读性考虑,一般认为对于二元运算符,将其重载为友元函数形式更好些。但重载“=”运算符必须用成员函数,不能用非成员的友元函数。

例10-6 如果A和B都是m行n列矩阵,且它们对应元素相等,即aij=bij(i=1,2,...m; j=1,2,...n),则称A与B相等,记为A=B。试定义一矩阵类,对“==”运算符重载,实现两矩阵A与B相等关系的判断。 解:具体程序如下:

94

《C++面向对象程序设计》 函授自学指导书

#include #include class Matrix {

private:

int row, col; // row:矩阵的行数,col;矩阵的列数 int *elems; //指向矩阵元素 pub1ic:

Matrix():row(0),col(0) //构造初始化表 {

elems=new int(NULL); }

Matrix(int m,int n,int a[]):row(m),col(n) {

int *p1. *p2=a, num=m*n;

elems=new int[num]; //分配存储空间 if(!elems) {

cout<< \"Allocation Error !\\n\"; exit(1); }

p1=elems;

for(int i=0; i~Matrix() {

row=col=0; delete [ ]elems; }

int operator ==(Matrix &b); };

int Matrix::operator==(Matrix &b) {

int *p1=elems,*p2=b.elems; int i,num=row*col;

if(row= =b. row& &col= =b.col) {

for(i=0;ireturn((ireturn(0); }

void main() {

int a[ ]={ 1,2,3,4,4, 10}, b[ ]={ 1,2,3,4,5,10}; Matrix A(3,2,a); Matrix B(3,2,b);

95

《C++面向对象程序设计》 函授自学指导书

if(A= =B)

cout<<\"矩阵A与矩阵B相等! \"<cout<<\"矩阵A与矩阵B不相等! \"<}

说明:在运算符重载函数operator==(Matrix &b)中,首先判断矩阵A和B的行数、列数是否分别相等,若不相等,函数返回0(假);如果相等,则逐个判断对应元素是否相等,函数采用了循环结构,当所有对应元素都相等时,函数返回1(真),在进行比较过程中,一旦出现数值不等则由break语句终止循环。

例 10-7 应用 C+十的多态性,编程求球体和圆柱体的体积和表面积。 解:根据几何知识,球的半径为 r,则球的体积 Vs=4πr3/3,表面积 Ss=4πr2;圆柱的底面圆半径为r,高为h,则圆柱的体积vC=πr2h,表面积Sc=2πr(r+h)。由于球体和圆柱体均可从国继承而来,所以先定义基类rbase,在基类中定义两个虚函数volume()和area(),球体类sphere及圆柱体类column 由rbase派生得到,在派生类中对虚函数重新定义,用于分别计算球体、圆柱体的体积和表面积。

#include const double PI=3. l4l59; class rbase {

protected: float radius; publlc:

rbase(float a=0.0)fradius(a) { } virtual double area() {

return(PI*radius *radilis); }

virtual double volume() {

return(0.0); }

};

class sphere:public rbase {

public:

sphere(float a):rbase(a) { }

double area ( ) {

return (4. 0 * PI *radi us *radius ); }

double volume() {

return(4.0*PI*radius*radius*radius); }

};

class column:public rbase {

96

《C++面向对象程序设计》 函授自学指导书

private: float h; public:

co1umn(float a,float b):rbase(a) {

h=b; }

double area() {

return 2.0* PI*radius* h+radius); }

double volume() {

return(PI * radiu s *radius *h); }

};

void main() {

rbase *p; sphere s (2); p=&s;

cout<<\"体积:\" <volume()<area()<cout<< \"体积:\"<volume()<area()<说明:程序中所定义的基类指针p的作用是用来指向从基类rbase派生出的 sphere类和 column类,当基类指针 p指向包含虚函数的 sphere、column类对象时,C++会根据指针p所指向的对象的类型自动决定调用何种形式的函数。 例10-8 若一平面图形由若干互不相交的圆形和矩形组成,试通过定义纯虚函数的方法,求此平面图形的面积。

解:定义一个基类shape,其中定义一个抽象平面的面积函数area(),构成平面图形的圆形类和矩形类由shape派生而来,在实际调用面积函数时,利用动态联编的方法获得派生类具体函数。具体程序如下:

#include const double PI=3. 14159;

class shape { // 定义抽象基类shape public:

virtual double area(void)=0; // area()为纯虚函数 vittual void show(void)=0; //show()为纯虚函数 };

class rectangle:public shape { private: float l,w;

97

《C++面向对象程序设计》 函授自学指导书

public:

rectangle(f'loat a=0,float b=0){

l=a; w=b; }

double area() {

return(l*w); }

void show() {

cout<<\"矩形的面积是:\"<class circle:public shape {

private: float r; public:

circle(float rd=0) {

r=rd; }

double area() {

return(PI*r*r);

}

void show() {

cout<<\"圆的面积是: \"<double sum(shape *p [ ],int n) {

double sum=0.0; for(int i=0;iarea(); return sum; }

void main() {

shape *gp[4]; int i;

// 图形由两个圆和两个矩形组成 gp[0]=new rectangle(3.0,4.0); gp[1]=new rectangle(6.0,7.0); gp[2]=new circle(3.0); gp[3]=new circ1e(4.0);

for(i=0,i<4;i++) gp[i] ->show(); //显示每个图形的面积 cout<<\"图形的总面积是: \"<98

《C++面向对象程序设计》 函授自学指导书

以本程序数据为例,其输出为: 矩形的面积是: 12 矩形的面积是: 42

圆的面积是: 28.2743 圆的面积是: 50.2655 图形的总面积是:132.54

说明:gp[4]是指针数组,其元素是指向基类对象或派生类对象的指针,程序运行过程中,C+十所选择的成员函数show()和area()将取决于指针所指向的对象所在的类,而不是是取决于指针定义时的类型。

【思考题】

1.编译时的多态性与运行时的多态性有何区别?

2.试比较成员运算符函数与友元运算符函数的用法特点。

3.下面程序段定义了复数类complex,将操作符“+”以成员函数形式重载;实现两复数相加。试采用友元函数改写该程序中的运算符重载函数。 class complex{ float real,imag; public:

complex(float r=0,float i=0):real(r),imag(i){ } complex operator+(complex c){

return complex(real+c.real,imag+c.imag); }

vold show() {

if(imag>=0.0)

cout<cout<};

4. C++中,运算符“++”和“--”与操作数的位置关系有前置和后置两种形式。定义一个复数类,将操作符“++” 和“--” 重载;实现复数的增量和减量运算。

5. 重载运算符“+” 和“-”;计算平面上两个矢量加和减运算,并编写主程序进行调试。

6. 定义生日类Brithday:

class Birthday { private:

int year, month, day ; public:

Birthday(int y, int m, int d); //构造函数,年月日数据由y,m,d给出 Birthday(char *str); //构造函数,年月日由y/m/d的字符串形

式给出

... ... };

试将运算符“>”、“<”、“==”进行重载,实现两生日数据的大小,关系判断。如表达式 Birthday(\"02/10/01\")>Birthday(\"01/01/10\"),表明 2002年10月 1日在2001年1月 10日之前;表达式Birthday(\"05/10/01\")

99

《C++面向对象程序设计》 函授自学指导书

==Birthday(5,10,1),表明两生日是同一天。 7.下面程序段虚函数被重新定义的方法正确吗?

class c1 {

public:

virtual float func1(float f)=0; virtual friend func2(int a, int b); };

class derived: public c1 {

public:

int func(int a, int b) {

return(a*b);

};

8.采用虚函数的方法计算三角形、矩形和圆的面积。

9.试以纯虚函数的方法,求任意给定函数 y=f(x) 在区间[a,b]上的定积分。其中求函数定积分的梯形法是:将积分区间[a,b]分成n个小区间;则每个区间的宽度为(b-a)/n,将n个曲边梯形近似认为梯形,计算出每个小梯形的面积,并将n个梯形面积累加起来得到的总面积,作为定积分的值、显然,n愈大,积分值含精确、请编写程序求下列两函数y1=ex、y2=3x2+x+1在区间[0,1]上的定积分。

第十一章 文件与流类库 【学习要点】

l.掌握文件的打开和关闭、读和写的操作方法。 2.掌握文本文件和二进制文件。 3.学会创建自己的I/O操作符。 4.格式化I/O系统。

【例题分析】

一、阅读题

例11-1 阅读如下程序,指出其输出结果。

#include #include void main() {

int n= 15;

cout<100

《C++面向对象程序设计》 函授自学指导书

cout<}

解:这是一个输入输出格式控制的例子。本程序输出结果为: f

$$$$4321 二、编程题

例11-2 编写一程序,在屏幕上显示任意文件的内容。 解:#include #include #include

void main(int argc, char *argv[]) {

char ch;

if(argc!=2) 0{

cout<<\"用法:Disp文件名\\n\"; exit(1 ); }

ifstream in;

in.open(argv [ 1 ],ios:: in); if(!in) {

cout<<\"不能打开文件\" <while(in) { in.get(ch); cout<in.close(); }

说明:程序采用了命令行参数形式,程序执行时需传递一个被显示内容的文件名,此时,argc的值是命令行中一个可执行文件名与被显示文件名个数之和,即argc应等于2。若可执行程序文件名为Disp.exe,则命令行参数接收后,字符型指针数组argv的argy[0]指向字符串“Disp”,argv[1]指向被显示文件名.

例11-3 编写一程序,将0~255之间的所有字符写入文件chars.txt中。 解: #include #include #include void main() {

ofstream out(\"chars.txt\"); if(!out) {

cout<<\"不能打开输出文件!\\n\"; exit(1); }

int ch;

for(ch=0;ch<=255;ch++ ) out.put((char) ch); out.close(); }

101

《C++面向对象程序设计》 函授自学指导书

例11-4 编写文件复制程序,一次一个字符地从一个文件中读人数据,并写人另一个文件中。

解:C+十可以对文件进行输入和输出操作,如果要为输入打开一个文件,可使用ifstream类;如果要为输出打开一个文件,可使用ofstream类;如果打开文件用于输入和输出,则可使用fstream类。 #include #include #include void main() {

char inFilename[12]; // 输入文件名 char outFilename[12]; // 输出文件名 ifstream inFp; ofstream outFp; char inChar;

cout<<\"输入源文件名: \"; cin>>inFilename;

inFp. open(inFile name, ios:: in); if(!inFP) {

cout<<\" \\n\\n\" <cout<<\"输入备分文件名:\"; cin>>outFilename;

outFp. open (outFilename, ios:: out); if(!outFp) {

cout<<\"\\n\\n不能创建备份文件\\n\"; exit(1 ); }

cout<<\"\\n正在备分...\\n\"; while(inFp.get(inChar)) outFp例11-5 学生情况记载表有姓名、学号、性别和成绩等四项。编写一程序用于此表的数据输入和数据显示。

解:学生情况记载表由姓名、学号、性别和成绩等项构成,若我们定义下面的结构:

struct Student { char Name[20]; char lD[8]; char Sex; int Score; };

对此结构类型数据的输出和输入,Printf()函数和scanf()函数是无法接受的,因为printf()、scanf()只能识别系统预定义的类型,而无法对用户自定义的新数据类型进行扩充。为此,我们可以定义一个类StudInf,将姓名、学

102

《C++面向对象程序设计》 函授自学指导书

号、性别和成绩作为它的数据成员,使用C++的输入输出系统,通过重载“<<”和“>>”运算符来解决以上问题。

定义输出运算符“<<”重载函数的一般格式如下:

ostream &operator<<(ostream &stream, class_name obj) {

// 操作代码 return stream; }

定义输入运算符\">>\"重载函数的一般格式如下:

istream &operator>>(istream &stream, class_name &obj) {

// 操作代码 return stream; }

完整程序如下:

#include #include #include class StudInf { private:

char Name[20]; char ID[8]; char Sex; int Score; public:

StudInf() { };

StudInf(char *nm,char *nb,char sx,int sc):Sex(sx),Score(sc) {

strcpy(Name,nm); //字符串复制,不能用\"=\"赋值 strcpy(lD,nb); }

friend ostream &operator<<(ostream &stream,StudInf s); friend istream &operator>>(istream &stream,StudInf &s); };

ostream &operator<<(ostream &stream, StudInf s) {

stfeam<istream &operator>>(istream &stream, StudInf &s) {

cout<<\"输入姓名:\"; stream>>s.Name;

103

《C++面向对象程序设计》 函授自学指导书

cout<<\"输入学号:\"; stream>>s.ID;

cout<<\"输入性别:\"; stream>>s.Sex; cout<<\"输入成绩:\"; stream>>s. Score; cout<<\"\\n\"; return stream;

}

main() {

StudInf a;

fstream sb(\"book\if(!sb) {

cout<<\"不能打开文件\\n\"; return(1); }

for(;;) { char c; do {

cout<<\"1.输入信息 \\n\"; cout<<\"2.显示信息\\n\"; cout<<\"3.退 出\\n\";

cout<<\"\\n 键入选择(1,2,3): \"; cln>>c;

} while(c<'1'||c>'3'); switch(c) { case '1': cin>>a;

cout<<\"输入信息是: \"; cout<break;

case '2': char ch;

sb.seekg(0,ios::beg);

while(!sb.eof()) {

sb.get(ch); cout<sb.clear(); cout<case'3': sb.close();

return(0);

} } }

104

《C++面向对象程序设计》 函授自学指导书

【思考题】

1.编程输出下面的数据:

abcdefghi012345678 0x45 4567.89

123 * * * * * * * * * * * * * * * * 123

2.编写一程序,读人用户输入的口令,将其与保存在口令文件password.txt中的正确口令进行比较;最后将比较结果通知用户。

3.请求用户输入4个字符串;编程实现将其中最长的一个字符串显示出来,并将其写入文件char.txt中。

4.编写一程序从一个由英文字母、数字、符号等字符组成的文件中读出数据,将其中的字母大小写变反后,写入新创建的另一个文件中。

5.编写一教师用的成绩记录程序,允许教师最多输入 10个学生的成绩。每个学生每学期有三门成绩;学生名和三门成绩保存于一结构数组中,这些数据存于磁盘。要求程序是菜单驱动的,菜单包含以下3个选择项: (1)增加学生。 (2)查看文件数据。

(3)显示各成绩并计算出全班平均成绩。

105

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- yrrd.cn 版权所有

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务