一、 填空题(25小题,共50分) (以下每小题1分,共10分) 1. 在C++中,函数的参数有两种传递方式,它们是值传递和 地址或指针或引用传递 。 2. 当一个成员函数被调用时,该成员函数的 this指针 指向调用它的对象。 3. 在基类和派生类中,派生类可以定义其基类中不具备的数据和操作。对两个有相同名字的数据成员进行访问时,如果没有 作用域分隔符限定时 ,对此数据成员的访问将出现歧义。 4. 拷贝构造函数使用 引用 作为参数初始化创建中的对象。 5. 在公有继承的情况下,基类数据成员在派生类中的访问权限 保持不变 。 6. 描述命题”A小于B或小于C”的表达式为 A<B||A<C 。 7. 用new申请某一个类的动态对象数组时,在该类中必须能够匹配到 没有形参的或缺省参数 构造函数,否则应用程序会产生一个编译错误。 8. 静态数据成员在类外进行初始化,且静态数据成员的一个拷贝被类的所有对象 共享 。 9. 为了避免可能出现的歧义,C++对if…else语句配对规则规定为:else总是与 与最近的if 配对。 10. 设”int a=3,b=4,c=5;”,表达式”(a+b)>c&&b==c”的值是 0 。 (以下每小题2分,共20分) 11. 面向对象的程序设计有四大特征,它们是抽象、封装、 继承 、 多态 。 12. 在Visual C++中,定义重载函数时,应至少使重载函数的参数个数或参数类型 不同 ;在基类和派生类中,成员函数的覆盖是指 派生类成员函数与在基类被覆盖的成员函数名、参数个数、参数类型和返回值类型均相同 。 13. 构造函数与析构函数除功能不同外,在定义形式上,它们的区别还包括构造函数名与类名相同,而析构函数名是在类名前加一个~、 析构函数没有参数 、 析构函数可以定义为虚函数 、无返回值、不能被重载、一个类中只有一个析构函数 14. 动态联编要满足两个条件,它们是 被调用的成员函数是虚函数 、 用对象的指针或引用调用成员函数 。 15. 在C++类中,有一种不能定义对象的类,这样的类只能被继承,称之为 抽象类 ,定义该类至少具有一个 纯虚函数 。 16. 在C++类中,const关键字可以修饰对象和成员函数,const对象不能 被修改 ,const成员函数不能 修改类数据成员 。 17. 举出C++中两种用户自定义的数据类型: 类 、 枚举 18. C++中没有字符串类型,字符串是通过 字符数组 来表示的,每一个字符串都有一个结尾字符 /0 。 19. C++中没有输入输出语句,输入输出是通过 输入输出库 实现的, 写出一条打印整型变量n的输出语句:cout<<n; 20. 举出C++中两种代码复用的方式: 继承 、 复用 。 (以下每小题4分,共20分) 21. 下面程序的运行结果是 3 。 #include <stdio.h> void main() { char a=’a',b=’j'; float x; x=(b-a)/('F’-'A’); printf(“%d/n”,(int)(3.14*x)); } 22. 下面程序的运行结果是2 5 8 11 14。 #include “iostream.h” void main( ) { int i=1; while (i<=15){ i++; if (i%3!=2) continue; else cout <<”i=”<<i<<endl; } } 23. 下面程序的运行结果是________。 #include “iostream.h” class test { private: int num; float fl; public: test( ); int getint( ){return num;} float getfloat( ){return fl;} ~test( ); }; test::test( ) { cout << “Initalizing default” << endl; num=0;fl=0.0; } test::~test( ) { cout << “Desdtructor is active” << endl; } void main( ) { test array[2]; cout << array[1].getint( )<< ” ” << array[1].getfloat( ) <<endl; } Initalizing default Initalizing default 0 0 Desdtructor is active Desdtructor is active 24. 下面程序的运行结果是________。 #include <iostream.h> class A { public: A(){cout<<”A::A() called./n”;} virtual ~A(){cout<<”A::~A() called./n”;} }; class B:public A { public: B(int i){ cout<<”B::B() called./n”; buf=new char;} virtual ~B() { delete []buf; cout<<”B::~B() called./n”; } private: char *buf; }; void fun(A *a) { delete a; } void main() { A *a=new B(15); fun(a); } A::A() called. B::B() called. B::~B() called. A::~A() called. 25. 下面程序的运行结果是________。 #include <stdio.h> int a[ ]={1,3,5,7,9}; int *p[ ]={a,a+1,a+2,a+3,a+4}; void main( ) { printf(“%d/t%d/t%d/n”,a[4],*(a+2),*p[1]); printf(“%d/t%d/t%d/n”,**(p+1)+a[2],*(p+4)-*(p+0),*(a+3)%a[4]); } 9 5 3 8 4 7
二、 问答题(每小题5分,共20分) 1 若程序员没有定义拷贝构造函数,则编译器自动生成一个缺省的拷贝构造函数,它可能会产生什么问题? 解答要点:缺省的拷贝构造函数只会拷贝存储区的内容,如果其中有引用的话,它是不拷贝的,就造成了两个类的实例引用了同一个对象,导致运行出错 2简述成员函数、全局函数和友元函数的差别。 解答要点:以下几点必须说清楚: 成员函数:定义类的时候,定义了public访问级的函数,可以访问类的所有数据成员,也可以调用该类的其他成员函数; 全局函数:定义在主函数和类定义之外的函数,在任何地方允许被调用,但是过多的全局函数导致程序臃肿; 友元函数:由于通过类的实例并不能访问到类的私有成员,如果在类定义之内定义友元函数,在类的实例中就可以通过友元函数访问私有成员,该函数需要friend关键字声明 3简述结构化的程序设计、面向对象的程序设计的基本思想。 解答要点:结构化的程序设计将数据和对数据的操作分离,程序是由一个个的函数组成的,面向对象的程序设计将数据和操作封装在一起,程序是由一个个对象组成的,对象之间通过接口进行通信,它能够较好地支持程序代码的复用。 4结构struct和类class有什么异同? 解答要点:struct和class都可以定义类,但是缺省访问权限说明时,struct的成员是公有的,而class的成员是私有的。在C++中,struct可被class代替。 三、找出下面程序(或程序段)中的语法错误,并予以纠正(每小题4分,共8分) (1)程序功能是倒序输出各给定的字符串。 #include <stdio.h> void main() { char str[5][ ]={“First”,”Second”,”Third”,”Forth”,”Fifth”}; char *cp[ ]={str[4],str[3],str[2],str[1],str[0]}; int i; while(i<=5) { printf(“%c “,*(cp+i)); i++; } } ① “char str[5][ ]={“First”,”Second”,”Third”,”Forth”,”Fifth”};”应为 “char str[5][10 ]={“First”,”Second”,”Third”,”Forth”,”Fifth”};” ② “while(i<=5)”应为”while(i<5)” ③ “printf(“%c “,*(cp+i));”应为”printf(“%s”,*(cp+i));” ④ “int i;”应为”int i=0;” (2)程序功能是将各个平方根值放入数组中。 #include <stdio.h> void main() { int max,a,i; scanf(“%d%d”,max,a); double x[max]; for (i=0;i<max;i++) x=sqrt(a*i); } ① 增加”#include <math.h>” ② “scanf(“%d%d”,max,a);”应为”scanf(“%d%d”,&max,&a);” ③ “double x[max];”改为: “double *x=new double[max];” … “delete []x;” 四、(8分)下列shape类是一个表示形状的抽象类,area( )为求图形面积的函数,total( )则是一个通用的用以求不同形状的图形面积总和的函数。请从shape类派生三角形类(triangle)、矩形类(rectangle),并给出具体的求面积函数 class shape{ public: virtual float area( )=0; };
float total(shape *s[ ],int n) { float sum=0.0; for(int i=0;i<n;i++) sum+=s->area( ); return sum; } class Triangle:public Shape { public: Triangle(double h,double w){H=h;W=w;} double Area() const{return H*W*0.5;} private: double H,W; }; class Rectangle:public Shape { public: Rectangle(double h,double w){H=h;W=w;} double Area()const{return H*W;} private: double H,W; };
五、(6分)完成顺序查找函数f_seq( )。其过程是:从表头开始,根据给定的模式,逐项与表中元素比较。如果找到所需元素,则查找成功,并打印出它在表中的顺序号。如果查找整个表仍未找到所需对象,则查找失败 #include <stdio.h> void f_seq(char *list[],char *object,int len) //list 指针数组,指向字符串 //object 模式串 //len 表的长度 { char **p; int strcmp(char *s,char *t); p=list; while (_____①______) //p<list+len if (strcmp(*p,object)==0) break; else ______②_______; //p++ if (p<list+len) printf( “Success! **% d/n”,p-list); else printf(“Unsuccess!/n”); } int strcmp(char *s,char *t) { for (;*s==*t; s++,t++) if (*s==’/0′) return(0); return(_____③______); //s-t或*s-*t或1 } 六、(8分)完成使链表逆置函数reverse,若有链表: 链表结点的结构如下: struct node { int num; struct node *next; } struct node* reverse(struct node *head) //head 链表头结点 { struct node *p,*temp1,*temp2; if(head==NULL____①____) return head; //||head->next==NULL p=head->next;head->next=NULL; while(____②____) //p!=NULL或p { temp1=head; ____③____; //head=p; temp2=p; p=p->next; ____④____; //temp2->next=temp1;或head->next=temp1; }//Match while statenment return head; //返回逆置后的链表的头结点 }
一、选择题(50分,每小题2分) 下列各题A)、B)、C)、D)四个选项中,只有一个选项是正确的。 (1)下列有关内联函数的叙述中,正确的是 ( D ) A)内联函数在调用时发生控制转移 B)使用内联函数有利于代码重用 C)必须通过关键字inline来定义 D)是否最后内联由编译器决定 (2)下列情况中,哪一种情况不会调用拷贝构造函数 ( B ) A)用派生类的对象去初始化基类对象时 B)将类的一个对象赋值给该类的另一个对象时 C)函数的形参是类的对象,调用函数进行形参和实参结合时 D)函数的返回值是类的对象,函数执行返回调用者时 (3)以下哪一关键字可用于重载函数的区分( C ) A)extern B)static C)const D)virtual (4)下列有关数组的叙述中,正确的是( B ) A)C++中数组的存储方式为列优先存储 B)数组名可以作为实参赋值给指针类型的形参 C)数组下标索引从1开始,至数组长度n结束 D)数组指针的语法形式为:类型名 *数组名[下标表达式]; (5)下列有关继承和派生的叙述中,正确的是( C ) A)派生类不能访问通过私有继承的基类的保护成员 B)多继承的虚基类不能够实例化 C)如果基类没有默认构造函数,派生类就应当声明带形参的构造函数 D)基类的析构函数和虚函数都不能够被继承,需要在派生类中重新实现 (6)实现运行时多态的机制是( A ) A)虚函数 B)重载函数 C)静态函数 D)模版函数 (7)下列字符串中,正确的C++标识符是( D ) A)enum B)2b C)foo-9 D)_32 (8)若有下面的函数调用: fun(a+b, 3, max(n-1, b)); 其中实参的个数是( A ) A)3 B)4 C)5 D)6 (9)以下哪个关键字对应的属性破坏了程序的封装性( B ) A)const B)friend C)public D)protected (10)以下哪个符号(或组合)是作用域限定符( C ) A)-> B). C):: D)[] (11)下列关于this指针的说法正确的是( B ) A)this指针存在于每个函数之中 B)在类的非静态函数中this指针指向调用该函数的对象 C)this指针是指向虚函数表的指针 D)this指针是指向类的函数成员的指针 (12)在下列关于C++函数的叙述中,正确的是( C ) A)每个函数至少要有一个参数 B)每个函数都必须返回一个值 C)函数在被调用之前必须先声明 D)函数不能自己调用自己 (13)下列运算符中,不能重载的是 ( C ) A)&& B)!= C). D)-> (14)对于类的常成员函数的描述正确的是( A ) A)常成员函数不修改类的数据成员 B)常成员函数可以对类的数据成员进行修改 C)常成员函数只能由常对象调用 D)常成员函数不能访问类的数据成员 (15)使用如setw()的操作符对数据进行格式输出时,应包含的头文件是( D ) A)iostream B)fstream C)stdio D)iomanip (16)若有以下类定义 class MyClass { public: MyClass() { cout << 1; } }; 则执行语句MyClass a,b[2],*p[2];后,程序的输出结果是( B ) A)11 B)111 C)1111 D)11111 (17)下面程序的输出结果是( B ) #include <iostream> using namespace std; int i = 0; int fun(int n) { static int a = 2; a++; return a+n; } void main() { int k = 5; { int i = 2; k += fun(i); } k += fun(i); cout << k; } A)13 B)14 C)15 D)16
(18)下面程序的输出结果是( A ) #include <iostream > using namespace std; void swap1( int &v1, int &v2) { int tmp = v2;v2 = v1;v1 = tmp; } void swap1( int *v1, int *v2) { int tmp= *v2;*v2 = *v1;*v1 = tmp; } void main() { int i = 10, j = 20; swap1(i,j); swap1(&i,&j); cout<<i<<”,”<<j<<endl; } A)10,20 B)20,10 C)10,10 D)20,20 (19)下面的程序段的运行结果为( D ) char str[] = “job”, *p = str; cout << *(p+2) << endl; A)98 B)无输出结果 C)字符’b’的地址 D)字符’b’ (20)下面程序的输出结果是( C ) #include <iostream> using namespace std; class A { public: A (int i) { x = i; } void dispa () { cout << x << “,”; } private : int x ; }; class B : public A { public: B(int i) : A(i+10) { x = i; } void dispb() { dispa(); cout << x << endl; } private : int x ; }; void main() { B b(2); b.dispb(); } A)10,2 B)12,10 C)12,2 D)2,2 (21)下面程序的输出结果是( C ) #include <iostream> using namespace std; class Base { public: Base(int i) { cout << i; } ~Base () { } }; class Base1: virtual public Base { public: Base1(int i, int j=0) : Base(j) { cout << i; } ~Base1() {} }; class Base2: virtual public Base { public: Base2(int i, int j=0) : Base(j) { cout << i; } ~Base2() {} }; class Derived : public Base2, public Base1 { public: Derived(int a, int b, int c, int d) : mem1(a), mem2(b), Base1(c), Base2(d), Base(a) { cout << b; } private: Base2 mem2; Base1 mem1; }; void main() { Derived objD (1, 2, 3, 4); } A)134122 B)123412 C)14302012 D)143212 (22)以下程序对一维坐标点类Point进行运算符重载,输出结果是( A ) #include <iostream> using namespace std; class Point { public: Point (int val) { x = val; } Point operator ++() { x++; return *this; } Point operator ++(int) { Point old = *this; ++(*this); return old; } Point operator +(Point a) { x += a.x; return *this; } int GetX() const { return x; } private: int x; }; int main() { Point a(10); cout << (++a).GetX(); cout << a++.GetX(); } A)1111 B)1011 C)1112 D)1010 (23)下面程序的输出结果是( C ) #include <iostream> using namespace std; class Base { public: virtual void f() { cout << “f0+”; } void g() { cout << “g0+”; } }; class Derived : public Base { public: void f() { cout << “f+”; } void g() { cout << “g+”; } }; void main() { Derived d; Base *p = &d; p->f(); p->g(); } A)f+g+ B)f0+g+ C)f+g0+ D)f0+g0+ (24)下面程序的输出结果是( C ) #include <iostream> using namespace std; int countp=0; class Point { int X,Y; public: Point(int x=0,int y=0) { X=x; Y=y;} Point(Point &p){X=p.X;Y=p.Y;countp++;} friend Point myfun(Point p1 ,Point p2 ,const Point &p3); }; Point myfun(Point p1,Point p2,const Point &p3) { Point tmp(p1.X+p2.X+p3.X,p1.Y+p2.Y+p3.Y); return tmp; } void main() { Point pp0,pp1(1,2),pp2(1); myfun(pp0,pp1,pp2); std::cout<<countp<<endl; } A)0 B)4 C)3 D)6 (25)下面程序的输出结果是( C ) #include <iostream> using namespace std; class Sample { friend long fun (Sample s) { if (s.x < 2) return 1; return s.x * fun(Sample(s.x-1)); } public: Sample (long a) { x = a; } private: long x; }; void main() { int sum = 0; for (int i=0; i<6; i++) { sum += fun(Sample(i)); } cout << sum; } A)120 B)16 C)154 D)34
二、填空题(20分,每空2分) (1)以下程序是用来计算小于16的整数的阶乘,请补充完整。 #include<iostream> using namespace std; const int ArSize =16; void main() { double fac[ArSize]; fac[1] =fac[0] =1.0; for(int i=2;i<ArSize;i++) fac = i*fac[i-1] ; } (2)下面是个Cat类的声明与使用,请补充完整。 #include <iostream> using namespace std; class Cat { static int count; public: Cat() { count++; cout << “Now cat number is” <<count << endl; } ~Cat() { count–; cout << ” Now cat number is ” << count << endl; } }; int Cat::count =0; int main() { Cat a, b, c; return 0; } (3)将下面的MyPoint类定义补充完整,使得程序的输出结果是(10,10)(5,5) #include <iostream> class MyPoint { public: MyPoint(int xx=5, int yy=5) { X = xx; Y = yy; std::cout<<”(“<<X<<”,”<<Y<<”) “;} private: int X, Y; } ; void main() { MyPoint a(10,10),b; } (4)已知文件之间具有以下的包含关系(用#include指令):point.cpp 包含 point.h,point.cpp 包含 line.h,line.h包含 point.h。那么如下的point.h文件缺少什么语句,请补充完整。 // Point类的声明,point.h #ifndef _POINT_H_ #define _POINT_H_ class Point { … } ; #endif (5)下列函数的功能是判断字符串str是否对称,对称则返回true,否则返回false。请在横线处填上适当内容,实现该函数。 bool fun (char *str) { int i=0, j=0; while (str[j]) j++; for(j–; i<j && str==str[j]; i++, j–); return i>=j ; } (6)请将下列程序补充完整,使得输出结果为“Destructor Derived Destructor Base”。 #include <iostream> using namespace std; class Base { public: virtual ~Base () { cout << “Destructor Base”<< endl; } }; class Derived : public Base { public: ~Derived(){ cout << “Destructor Derived” << endl; } }; void main () { Base *pBase = new Derived; delete pBase ; } (7)如有下列程序: #include <iostream> using namespace std; class Demo { public: Demo(){cout<<”default constructor\n”;} Demo(const Demo &x){cout<<”copy constructor\n”;} }; Demo userCode(Demo b){Demo c(b);return c;} void main() { Demo a,d; cout<<”calling userCode()\n”; d = userCode(a); } 执行上面的程序的过程中,构造函数Demo()和Demo(const Demo &x)被调用的次数分别是 2 和 3 次。
三、程序题(30分,每题10分) (1)程序改错 每个注释“// ERROR”所在的一行语句存在错误。请改正这些错误,使程序的输出结果为: 00:00:00 01:37:19 注意:只需修改注释“// ERROR”所在的那一行语句,不要改动程序中的其他内容。 #include<iostream> #include<iomanip> using namespace std; class StopWatch //”秒表”类 { int hours; //小时 int minutes; //分钟 int seconds; //秒 public: StopWatch():hours(0), minutes (0), seconds(0){} void reset(){hours=minutes=seconds=0;} //前进1秒 StopWatch& operator++() // ERROR ① { if(seconds==60) // ERROR ② { seconds=0; if(++minutes==60) { minutes=0; ++hours; } } return *this; }
friend void show(StopWatch); }; void show(StopWatch watch) { cout<<setfill(‘*’); // ERROR ③ cout<<setw(2)<<watch.hours<<’:’ <<setw(2)<<watch.minutes<<’:’ <<setw(2)<<watch.seconds<<endl; } int main() { StopWatch sw; show(sw); for(int i=0;i<5839;i++) sw++; show(sw); return 0; } 解答: ①: StopWatch& operator++(int) (4分) ②: if(++seconds==60) (3分) ③: cout<<setfill(’0′); (3分) (2)语句填空 下面的程序设计了一个宠物类,请你在空行上填入合适的语句,使程序完整。(每空2分) #include <iostream> enum Pets_type{dog,cat,bird,fish}; class Pets { private: char *name; Pets_type type; public: Pets(const char *n=”sonny”,int type1 = 0); Pets(const Pets &s); Pets& operator=(const Pets &s); ~Pets(); }; Pets::Pets(const char *n,int type1) //构造函数 { name = new char[strlen(n) + 1]; strcpy(name,n); type = Pets_type(type1); } Pets::Pets(const Pets &s) //拷贝构造函数 { name = new char[strlen(s.name) + 1] ; strcpy(name,s.name); type = s.type; } Pets::~Pets() //析构函数 { delete[] name ; } Pets& Pets::operator =(const Pets &s) { if (this==&s) //确保不要向自身赋值 return *this; delete [] name; name = new char[strlen(s.name) + 1]; strcpy(name,s.name); type = s.type; return *this ; } void main() { Pets mypet1,mypet2(“John”,1),hispet(“Danny”,2); Pets youpet(hispet); mypet1 = youpet;} 3) 编写程序段 补充编制下列程序,其功能是从键盘读取任意长度的文本内容,将文本存放到Doc类的对象myDoc中。然后在显示器输出。 请在//******* begin ******和//******* end *******之间补充程序。 #include<iostream> #include<iomanip> #include<cstring> using namespace std; class Doc { private: static const int MaxLength; // 可能的最大文本字符串长度 char *str; // 文本字符数组首地址指针 int length; // 文本字符串长度 public: Doc(const char *s = “”); // 构造函数 ~Doc(); // 析构函数 // 重载istream的提取运算符 friend istream& operator>>(istream& is, Doc& doc); // 重载ostream的插入运算符 friend ostream& operator<<(ostream& os, Doc& doc); }; const int Doc::MaxLength=256; // 可能的最大文本字符串长度 //重载提取运算符,从输入流is提取字符串,存入参数doc中 istream& operator>>(istream& is, Doc& doc) { //提示:使用is.getline函数可以从is流提取字符串,包括空格。 //********************** begin ************************* char buffer[Doc::MaxLength]; is.getline(buffer, Doc::MaxLength); int inLen = (int)strlen(buffer); if (inLen > doc.length) { delete [] doc.str; doc.str = new char[inLen+1]; } strcpy(doc.str, buffer); doc.length = inLen; return is; //******************** end ***************************** } ostream& operator<<(ostream& os, Doc& doc) { os << doc.str; return os; } Doc::Doc(const char *s) : length((s!=NULL) ? (int)strlen(s) : 0) { str = new char[length + 1]; if (s != NULL) strcpy(str, s); else str[0] = ‘\0′; } Doc::~Doc() { delete [] str; } void main() { Doc myDoc(“Initial String”); cin >> myDoc; cout<< myDoc;
|