一、 对错题。判断以下说法的正确性,在下面表格中对应的编号下面写上“对”或“错”。(20分,每个题目2分)
题号 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
对/错 |
对 |
错 |
对 |
错 |
错 |
对 |
错 |
对 |
错 |
对 |
1. 说明函数原型时不需要指明每个函数参数的名字,只需要说明每个参数的类型和返回值类型就可以了。
2. 所有的表达式都有值。
3. 程序的编译是以文件为单位的,因此将程序分到多个文件中可以减少每次对程序修改所带来的编译工作量。
4. 类的静态数据成员需要在定义每个类的对象时进行初始化。
5. 基类中被说明为protected和private的成员只能被其派生类的成员函数访问,不能被其它的函数访问。(别忘了友元)
6. 当将一个类S定义为另一个类A的友元类时,类S的所有成员函数都可以直接访问类A的所有成员。
7. 当函数的返回值是数组类型的,传递的是数组第一个元素的地址。
8. 如果派生类的成员函数的原型与基类中被定义为虚函数的成员函数原型相同,那么,这个函数自动继承基类中虚函数的特性。
9. 字符串“hello,world”在内存中存放时,占用11个字节的空间。(0结束符不能丢)
10.用new动态申请的内存空间,必须用delete来释放 。
------------------------------------------------------------------------
二、简单编程题。根据程序要求,写出函数的完整定义。(共25分)
1.(本小题15分)写一个函数,找出给定字符串中数字字符(即’0’—‘9’这10个数字)的个数(如字符串”olympic2000”中数字字符的个数为4个。函数的原型为:
int CalcDigital(char *str);
函数参数:str为所要处理的字符串。
函数返回值:所给字符串中数字字符的个数。
int CalcDigital(char *str)
{
//在下面写出程序的实现
}
1. 程序为:
int CalcDigital(char *str)
{
//判断字符指针是否为空
if(str==NULL)
return 0;
//记录数字字符个数的变量
int num_of_digital=0;
//依次检查各个字符,如果是数字,则总数加1
for(int i=0; str[ i ]!=0x0; i++)
if(str[ i ]<='9' && str[ i ]>='0')
num_of_digital++;
//返回数字字符个数
return num_of_digital;
}
2.(本小题10分)用递归函数完成以下运算:
sum(n)=12+22+…+n2
函数的原型如下:
long sum(int n);
该函数完成12+22+…+n2的运算,并返回运算结果,其中n>0。
提示:你可以使用递归表达式:sum(n)=sum(n-1)+n2
long sum(int n)
{
}
2. 程序为:
long sum(int n)
{
if(n==1)
return 1;
else
return n*n+sum(n-1);
}
三、 (本小题30分)
下面的文件queue.h是一个队列类模板Queue的完整实现。在这个文件中首先定义了一个队列元素类模板QueueItem,然后在这个类的基础上定义了队列类模板Queue。在Queue中使用链表存放队列的各个元素,front指针指向链表的第一个节点元素,back指针指向链表的最后一个节点元素,成员函数add()将一个新节点元素加入到队列结尾,remove()从队列开头删除一个节点元素。为方便起见,程序中加上了行号。阅读程序,根据程序后面的问题作出相应解答。
/*****************文件queue.h**************************************/
/******************************************************************/
1 template<class Type>
2 class Queue;
3 /**********定义模板类QueueItem*******************************/
4 template <class Type>
5 class QueueItem
6 {
7 public:
8 QueueItem(const Type &elem):item(elem){}
9 QueueItem(){}
10 private:
11 Type item;
12 QueueItem *nextItem;
13 friend class Queue<Type>;
14 };
15 /***************定义模板类Queue*****************************/
16 template<class Type>
17 class Queue{
18 public:
19 Queue():front(NULL),_______(A)_______{}
20 ~Queue();
21 Type remove();
22 void add(const Type &);
23 bool is_empty()const {return ____(B)____;}
24 private:
25 QueueItem<Type> *front;
26 QueueItem<Type> *back;
27 };
28 //模板类Queue的函数成员remove()的实现
29 //从队列头取出一个节点,并返回该节点的值
30 template<class Type>
31 Type Queue<Type>::remove()
32 {
33 QueueItem<Type> *pFront; //指向头节点的临时指针
34 Type retVal; //返回值
35 ____(C)____;
36 retVal=pFront->item;
37 front=pFront->nextItem;
38 delete pFront;
39 return retVal;
40 }
41 //模板类Queue的函数成员add()的实现
42 template<class Type>
43 void Queue<Type>::add(const Type& newItem)
44 {
45 QueueItem<Type> *pNew=new QueueItem<Type>;
46 pNew->item=newItem;
47 ____(D)____;
48 if(front==NULL)
49 front=back=pNew;
50 else
51 {
52 back->nextItem=pNew;
53 ____(E)____;
54 }
55 }
56
57 template <class Type>
58 Queue<Type>::~Queue()
59 {
60 QueueItem<Type> *p=front, *q;
61 while(p!=NULL)
62 {
63 q=p->nextItem;
64 delete p;
65 p=q;
66 }
67 }
问题1:(每个填空3分,共15分)程序中有几处填空,将它们完成。
(A)______________________________________________
(B)______________________________________________
(C)______________________________________________
(D)______________________________________________
(E)______________________________________________
问题2:(本小题3分)题中程序第1、2行为什么要说明一下类模板Queue?如果没有这两行语句,程序还正确吗?
答:
问题3:(本小题4分)程序第22、23行各有一个const,它们各自表示什么含义?
答:
问题4:(本小题3分)程序中模板类Queue的析构函数主要做了什么事情?为什么要这么做?
答:
问题5:(本小题5分,每答对一个给1分)下面的程序使用了queue.h文件中定义的类模板,说明程序中哪些定义队列对象的语句是不正确的,哪些是正确的?
#include “queue.h”
void main()
{
Queue q1;//1
Queue<int> q2; //2
Queue<int> q3(100); //3
Queue<int> q4[100]; //4
Queue<int> q5=new Queue<int>; //5
//…
delete q5;
}
答:
语句号 |
1 |
2 |
3 |
4 |
5 |
对/错 |
|
|
|
|
|
答案:
问题1:答案为:
(A)back(NULL)
(B)front == NULL 或 back == NULL
(C)pFront = front
(D)pNew->nextItem = NULL
(E)back = pNew
问题2:
答:不正确。因为在类QueueItem模板类的定义中用到了模板类Queue,而此
时Queue还没有定义,所以要先声明一下,告诉编译程序Queue是一个模板类
,它将在程序的其他地方定义。如果没有这个说明,编译程序就不知道标识
符Queue代表什么样的含义了。
问题3:
答:第22行的const修饰的是函数的参数,表示在这个函数体中不能改它所修
饰的参数所对应的实际参数的值。
第23行的const修饰的是模板类Queue的成员函数is_empty(),它表示在函数i
s_empty()的函数体中不能改变任何数据成员的值。
问题4:
答:析构函数中主要是释放链表中存放的各个节点的空间。因为Queue对象在
其生存期间可能加入了很多节点,从堆中申请了一些内存空间,这些空间应
该随着对象的消亡而释放掉,所以需要在析构函数中来释放这些空间。
问题5:
语句号 |
1 |
2 |
3 |
4 |
5 |
对/错 |
错 |
对 |
错 |
对 |
对 |
四、 (本小题16分)阅读下面的程序,写出程序运行的结果。
/*************************************************************/
#include <iostream.h>
class A{
private:
//其它成员
public:
virtual void func(int data){cout<< "class A:"<<data<<endl;}
void func(char *str){ cout<<"class A:"<<str<<endl; }
};
class B: public A{
//其它成员
public:
void func() {cout<<"function in B without parameter! /n";}
void func(int data) { cout<<"class B:"<<data<<endl; }
void func(char *str){ cout<<"class B:"<<str<<endl;}
};
int main(int argc,char *argv[])
{
A *pA;
B b;
pA=&b;
pA->func(1);
pA->func("haha");
return 0;
}
/*******************************************************************/
问题1:(本小题4分)在下面写出程序的运行结果:
问题2:(本小题2分)如下句所示,在函数main()中通过pA调用类B中定义的参数表为空的函数func() :
pA->func();
是否正确?
答:(正确/不正确)
问题3:(本小题10分)如果要记录已尼创建的A类的实例(对象)的个数,我们可以借助于类的静态成员。修改上面类A的定义,使得它包含一个私有的静态成员object_count,记录属于该类的对象的个数,然后为类A增加必要的成员函数,使得下面的程序:
void main()
{
A *pA=new A[3];
cout<<"There are "<<pA->GetObjectCount()<<"objects"<<endl;
delete []pA;
cout<<"There are "<<A::GetObjectCount()<<"objects"<<endl;
}
得到的输出为:
There are 3 objects
There are 0 objects
在下面写出类A的定义(将所有的函数成员实现写在类定义体中):
在下面写出初始化类的静态成员object_count的语句:
答案:
问题1:
答:输出结果为:
classB:1
classA:haha
问题2:
答:不正确。
问题3:类A的定义如下:
class A{
private:
static object_count;
//其它成员
public:
A(){ object_count++;}
~A(){ object_count--; }
static int GetObjectCount(){ return object_count; }
//其它函数
virtual void func(int data){cout<<"class A: "<<data<<endl; }
void func(char *str){ cout<<"class A: "<<str<<endl; }
};
object_count的初始化语句如下:
intA::object_count=0;
五、(本题共9分)
下面的程序定义了一个简单的SmallInt类,用来表示从-128到127之间的整数。类的唯一的数据成员val存放一个-128到127(包含-128和127这两个数)之间的整数,为了方便,类SmallInt还重载了一些运算符。阅读SmallInt的定义,回答题目后面的问题。
class SmallInt{
public:
SmallInt(int i=0);
//重载插入和抽取运算符
friend ostream &operator<<(ostream&os,const SmallInt &si);
friend istream &operator>>(istream &is, SmallInt &si);
//重载算术运算符
SmallInt operator+(const SmallInt &si){return SmallInt(val+si.val);}
SmallInt operator-(const SmallInt &si){return SmallInt(val-si.val);}
SmallInt operator*(const SmallInt &si){return SmallInt(val*si.val);}
SmallInt operator/(const SmallInt &si){return SmallInt(val/si.val);}
//重载比较运算符
bool operator==(const SmallInt &si){return (val==si.val);}
private:
char val;
};
SmallInt::SmallInt(int i)
{
while(i>127)
i-=256;
while(i<-128)
i+=256;
val=i;
}
ostream &operator<<(ostream &os,const SmallInt &si)
{
os<<(int)si.val;
return os;
}
istream &operator>>(istream &is,SmallInt &si)
{
int tmp;
is>>tmp;
si=SmallInt(tmp);
return is;
}
问题1:(本小题4分)上面的类定义中,重载的插入运算符和抽取运算符被定义为类的友元函数,能不能将这两个运算符定义为类的成员函数?如果能,写出函数原型,如果不能,说明理由。
答:
问题2:(本小题5分)为类SmallInt增加一个重载的运算符’+=’,函数原型:
class SmallInt{
public:
SmallInt &operator +=(const SmallInt &si);
//其它函数
private:
char val;
};
该函数将返回对当前对象的引用。如:
SmallInt si1(20),si2(13);
则表达式:
si1+=si2
将返回对象si1的引用,并且si1中的的值是si1.val和si2.val的值之和(但必须正规化为在-128至127之间)。
在下面写出重载的运算符+=的实现:
答案:
问题1:
答:不能将插入运算符和抽取运算符定义为类的成员函数。
因为这两个运算符对第一个运算数有特殊的要求,即必须分别是ostream和istream类的对象,而不能是用户自己定义的其它类,而类的成员函数默认的第一个参数为指向该类对象的指针类型,所以不符合插入和抽取运算符的要求。
问题2:
重载的运算符的实现如下:
SmallInt &SmallInt::operator+=(const SmallInt &si)
{
SmallInt tmp(val+si.val);
val=tmp.val;
return *this;
}
或
SmallInt &SmallInt::operator+=(const SmallInt &si)
{
val+=si.val;
if(val>127)
val-=256;
if(val<-128
val=256;
return *this;
}