前言
一、判断题
X 1.声明一个引用后,可以为该引用指定不同的引用对象。
√ 2.类可以定义多个构造函数,但只能有一个复制构造函数和一个析构函数。
X 3.若A类是B类的友元类,则B类的所有成员函数都可访问A类成员。
X 4.派生类能够继承基类中的友元函数。
√ 5.虚基类定义中关键字virtual只对其后的基类有效。
√ 6. 重载的运算符不可改变其原来的优先级和结合性。
X 7. 抽象类的派生类一定是非抽象类。
√ 8. 类模板的使用是首先将其实例化成一个模板类,再实例化对象。
√ 9. C++中的输入/出操作都是通过流类对象进行的。
X 10. 在try块中抛出异常,处理后,程序控制回到try块继续运行。
二、选择题
1.A类定义如下,编译时有错误的行是(B) 。
class A{
int a; //1行
public:
~A(int); //2行
A(int); //3行
};
A.1 B.2 C.3 D.1、2、3
2.在公有派生情况下,下面不正确的叙述是 (C) 。
A.派生类的对象可以赋给基类的对象
B.派生类的对象可以初始化基类的引用
C.派生类的对象可以直接访问基类中的成员
D.派生类对象的地址可以赋给基类的指针
3.有如下函数模板定义,则对func函数错误的调用是(A) 。
template T func(T x,T y){return x+y;}
A. func(2.3,5) B. func(int(2.3),5)
C. func(2.3,4.5) D. func(2.3,4.5)
4.输入/输出格式控制中, (B)是设置输出数据的宽度。
A. setfill() B.setw()
C. setbase() D.setprecision()
5.catch(…)表示能捕获任意类型的异常。该子句一般写在 (D)
A. 系统没有规定 B.第一个catch
C. 任意位置 D.最后一个catch
C 1:下列有关类的说法不正确的是( )。
A. 对象是类的一个实例
B. 任何一个对象只能属于一个具体的类
C. 一个类只能有一个对象
D. 类与对象的关系和数据类型与变量的关系相似
分析:对象是类的一个实例,类与对象的关系和数据与变量的关系相似,所以一个类可以有多个对象。
B 2:下面( )项是对构造函数和析构函数的正确定义。
A.void X::X(), void X::~X()
B.X::X(参数), X::~X()
C.X::X(参数), X::~X(参数)
D.void X::X(参数), void X::~X(参数)
分析构造函数无返回类型、可带参数、可重载;析构函数无返回类型、不可带参数、不可重载。
C 3:( )的功能是对象进行初始化。
A.析构函数 B. 数据成员 C.构造函数 D.静态成员函数
分析:当一个对象定义时,C++编译系统自动调用构造函数建立该对象并进行初始化;当一个对象的生命周期结束时,C++编译系统自动调用析构函数注销该对象并进行善后工作;
D 4:下列表达方式正确的是( )。
A.class P{ B. class P{
public: public:
int x=15; int x;
void show(){cout<<x;} void show(){cout<<x;}
}; }
C. class P{ D. class P{
int f; public:
}; int a;
f=25;void Seta (int x) {a=x;}
分析:在类体内不可对数据成员进行初始化;类定义结束时需用分号;只有类中的成员函数才能存取类中的私有数据。
D 5: 拷贝构造函数具有的下列特点中,( )是错误的。
A. 如果一个类中没有定义拷贝构造函数时,系统将自动生成一个默认的
B. 拷贝构造函数只有一个参数,并且是该类对象的引用
C. 拷贝构造函数是一种成员函数
D. 拷贝构造函数的名字不能用类名
分析:如果一个类中没有定义拷贝构造函数时,系统将自动生成一个默认的;拷贝构造函数只有一个参数,并且是该类对象的引用;拷贝构造函数的名字与类同名,并且不被指定返回类型;拷贝构造函数是一种成员函数。
B 6:关于静态成员的描述中,( )是错误的。
A. 静态成员可分为静态数据成员和静态成员函数
B. 静态数据成员定义后必须在类体内进行初始化
C. 静态数据成员初始化不使用其构造函数
D. 静态数据成员函数中不能直接引用非静态成员
分析:静态成员可分为静态数据成员和静态成员函数;静态数据成员被定义后,必须对它进行初始化,初始化在类体外进行,一般放在该类的实现部分最合适,也可以放在其他位置,例如,放在主函数前面等;静态数据成员初始化与该类的构造函数和析构函数无关;在静态成员函数的实现中,可以直接引用静态成员,但不能直接引用非静态成员。
A 7:关于友元的描述中,( )是错误的。
A. 友元函数是成员函数,它被说明在类体内
B. 友元函数可直接访问类中的私有成员
C. 友元函数破坏封装性,使用时尽量少用
D. 友元类中的所有成员函数都是友元函数
分析:友元函数是非成员函数,在类体内说明了,在类体外定义,定义和调用等同于一般的普通函数;由于它可以直接访问类的私有成员,因此破坏了类的封装性和隐藏性,尽量少用。
A 8对类的构造函数和析构函数描述正确的是()。
A. 构造函数可以重载,析构函数不能重载
B. 构造函数不能重载,析构函数可以重载
C. 构造函数可以重载,析构函数也可以重载
D. 构造函数不能重载,析构函数也不能重载
D 9类的析构函数的作用是( )。
A.一般成员函数 B.类的初始化 C.对象初始化 D.删除对象
C10假设OneClass为一个类,则该类的拷贝初始化构造函数的声明语句为( )。
(OneClass p); B. OneClass& (OneClass p);
C. OneClass(OneClass & p); D. OneClass (OneClass *p);
C 11下面对于友元函数描述正确的是( )。
A.友元函数的实现必须在类的内部定义
B.友元函数是类的成员
C.友元函数破坏了类的封装性和隐藏性
D.友元函数不能访问类的私有成员
C 14下面对静态数据成员的描述中,正确的是( )。
A.静态数据成员可以在类体内进行初始化
B.静态数据成员不可以在类体内进行初始化
C.静态数据成员不能受private控制符的作用
D.静态数据成员可以直接用类名调用
A 15下面对静态数据成员的描述中,正确的是( )。
A.静态数据成员是类的所有对象共享的数据
B.类的每一个对象都有自己的静态数据成员
C.类的不同对象有不同的静态数据成员值
D.静态数据成员不能通过类的对象调用
C 16下面对于析构函数的描述中不正确的是()。
A、析构函数是内置函数 B、析构函数与类名相同
C、析构函数不能有参数 D、析构函数在对象撤销时自动执行
- 下列的各类函数中, 不是类的成员函数。 ( C )
A) 构造函数 B) 析构函数 C) 友元函数 D) 拷贝初始化构造函数
注:可做友元的函数有普通函数和其它类的函数,所以不是本类内的成员函数。 - 作用域运算符“::”的功能是 。 ( D )
A) 标识作用域的级别的 B) 指出作用域的范围的
C) 给定作用域的大小的 D) 标识成员是属于哪个类的
注: “::”左边一般为类名,右边一般为成员变量和成员函数,它的功能就是标识是属于哪个类的;如果左边什么都不加,表示全局变量。 - 下列选项中, 是不正确的。 ( B )
A) 名空间是为了支持大规模程序的逻辑设计、排解名字冲突应运而生的
B) 名空间定义的关键词为typename
C) 名空间定义的关键词为namespace
D) 因为程序是跨文件的,所以名空间也是跨文件的 -
是析构函数的特征。 ( A )
A) 一个类中只能定义一个析构函数 B) 析构函数名与类名不同
C) 析构函数的定义只能在类体内 D) 析构函数可以有一个或多个参数
5. 下述静态数据成员的特性中, 是错误的。 ( D )
A) 说明静态数据成员时前边要加修饰符static
B) 静态数据成员要在类体外进行初始化
C) 引用静态数据成员时,要在静态数据成员前加<类名>和作用域运算符
D) 静态数据成员不是所有对象所共用的
注:静态成员都是隶属于类的,是所有同类对象共享的
6. 已知fl(int)是类A的公有成员函数,P是指向成员函数f1()的指针,采用 是正确的。( B )
A) p=fl; B) P=A::f1; C) P=A::fl(); D) P=f1();
注:指向普通函数的指针 int max(int a, int b){…} int (*p)(int, int); p=max;
指向类中公有函数的指针的赋值与上相同 指针名=类名::函数名,即 p=A::max;
7. 友元关系不能 ( C )
A) 是类是与类的关系 B) 是一个类成员函数与另一个类的关系
C) 继承 D) 提高程序的运行效率
注:友元关系可是一个类与另一个类的关系,也可以是一个类成员函数与另一个类的关系;利用友元的主要目的是提高程序的运行效率,通过友元访问类的私有数据(如同生活中通过人际关系得到内部消息或受益等)。
友元关系是不继承的。例:刘鹏是黄涛的朋友,可以分享黄涛的小秘密,但刘鹏不一定是黄小涛(假如黄小涛是黄涛的儿子)的朋友,不一定能分享黄涛儿子的小秘密。
8. 下列关于对象数组的描述中, 是错的。 ( D )
A) 对象数组的下标是从0开始的 B) 对象数组的数组名是一个常量指针
C) 对象数组的每个元素是同一个类的对象
D) 对象数组只能赋初值,而不能被赋值
9. 下列说明中 const char *ptr; ptr应该是 ( C )
A) 指向字符常量的指针 B) 指向字符的常量指针
C) 指向字符串常量的指针 D) 指向字符串的常量指针
注:使用const修饰指针时,由于const的位置不同,而含意不同。
下面定义的一个指向字符串的常量指针:
char * const prt1 = stringprt1; 已知:print()函数是一个类的常成员函数,它无返回值,下列表示中, 是正确的。 ( A )
A) void print()const; B) const void print();
C) void const print(): D) void print(const);
11. 关于new运算符的下列描述中, 是错的。 ( D )
A) 它可以用来动态创建对象和对象数组
B) 使用它创建的对象或对象数组可以使用运算符delete删除
C) 使用它创建对象时要调用构造函数
D) 使用它创建对象数组时必须指定初始值
注:用new创建对象数组时会自动调用无参的构造函数(或者有缺省值的构造函数) 例: Point *p = new Point[10]; 会调用10次无参的构造函数
12. 具有转换函数功能的构造函数,应该是 ( B )
A) 不带参数的构造函数 B)带有一个参数的构造函数
C) 带有两个以上参数的构造函数 D) 缺省构造函数
第2章 类和对象
一、选择题
1、( )不是构造函数的特征。
A、构造函数的函数名与类名相同;
B、构造函数可以重载;
C、构造函数可以设置缺省参数;
** D、构造函数必须指定类型说明。
2、下列关于构造函数的描述中,( )是正确的。
**A、构造函数可以设置缺省参数;
B、构造函数可以被继承;
C、构造函数可以对静态数据成员进行初始化;
D、构造函数可以说明为虚函数;
3、( )是析构函数的特征。
A、析构函数可以有一个或多个参数;
B、析构函数名与类名不同;
C、析构函数的定义只能在类体内;
**D、一个类中只能定义一个析构函数;
4、定义析构函数时,应该注意( )。
A、其函数名与类名完全相同;
B、函数返回类型是void类型;
**C、无形参,也不可重载;
D、函数体中必须有delete语句;
5、下列静态数据成员的特性中,( )是错误的。
A、说明静态数据成员时前边要加修饰符static;
B、静态数据成员要在类体外进行初始化;
**C、静态数据成员不是所有对象所共用的;
D、引用静态数据成员时,要在其名称前加<类名>和作用域运算符;
6、友元的作用是( )。
** A、提高程序的运用效率;
B、加强类的封装性;
C、实现数据的隐藏性;
D、增加成员函数的种类;
7、关于成员函数特征的下列描述中,( )是错误的。
** A、成员函数一定是内联函数;
B、成员函数可以重载;
C、成员函数可以设置缺省参数值;
D、成员函数可以是静态的;
8、已知:print()函数是一个类的常成员函数,它无返回值,下列表示中,( )是正确的;
** A、void print() const;
B、const void print();
C、void const print();
D、void print(const);
9、在( )情况下适宜采用inline定义内联函数。
A、函数体含有循环语句;
B、函数体含有递归语句;
**C、函数代码小,频繁调用;
D、函数代码多,不常调用;
10、假定AB为一个类,则执行“AB a(4) , b[3] , * p[2] ;”语句时,自动调用该类构造函数的次数为( )。
A、 3 ** B、 4 C、 6 D、 9
11、通常拷贝初始化构造函数的参数是( )。
A、某个对象名
B、某个对象的成员名
** C、某个对象的引用名
D、某个对象的指针名
12、有关类的说法不正确的是( )。
A、类是一种用户自定义的数据类型
B、只有类中的成员函数才能存取类中的私有数据
** C、在类中,如果不作特别说明,所有的数据均为私有类型
D、在类中,如果不作特别说明,所有的成员函数均为公有类型
13、在声明类时,下面说法正确的的是( )。
A、可以在类的声明中给数据成员赋初值
B、数据成员的类型可以是register
**C、public, private, protected这三种属性的成员可以按任意顺序出现
D、没有用public, private, protected定义的成员是公有成员
14、已知:p是一个指向类A数据成员m的指针,A1是类A的一个对象。如果要给m赋值为5, ( )是正确的。
A、A1.p=5
B、A1->p=5
** C、A1.*p=5
D、*A1.p=5
15、已知:类A中一个成员函数说明如下:
void Set(A&a); 其中,A&a的含义是( )。
A、指向类A的指针为a
B、将a的地址值赋给变量Set
** C、a是类A的对象引用,用来作函数Set()的形参
D、变量A与a按位相与作为函数Set()的参数
16、下列说明中const char *ptr; ptr应该是( )。
** A、指向字符型常量的指针
B、指向字符的常量指针
C、指向字符变量的指针
D、指向字符串的常量指针
17、采用函数重载的目的在于:( )
A、实现共享 B、减少空间
C、提高速度 ** D、使用方便,提高可读性
18、有关类和对象的说法下列不正确的是( )。
A、对象是类的一个实例
B、任何一个对象只能属于一个具体的类
** C、一个类只能有一个对象
D、类与对象的关系和数据类型和变量的关系相似
19、有以下类的说明,请指出错误的地方( )。
Class CSample
{ ** int a=2.5; A
CSample(); B
public:
CSample(int val); C
~CSample(); D
};
20、在类的定义形式中,数据成员、成员函数和( )组成了类定义体。
** A、成员的访问控制信息
B、公有消息
C、私有消息
D、保护消息
第3章 类的继承与派生
一、选择题
1、 从一个基类派生出的各个类的对象之间 (1) 。
A、共享所有数据成员,每个对象还包含基类的所有属性
B、共享部分数据成员,每个对象还包含基类的所有属性
** C、不共享任何数据成员,但每个对象还包含基类的所有属性
D、共享部分数据成员和成员函数
2、 C++的继承性允许派生类继承基类的 (2) 。
A、部分特性,并允许增加新的特性或重定义基类的特性
B、部分特性,但不允许增加新的特性或重定义基类的特性
** C、所有特性,并允许增加新的特性或重定义基类的特性
D、所有特性,但不允许增加新的特性或重定义基类的特性
3、 对于公有继承,基类的公有和保护成员在派生类中将 (3) 成员。
A、全部变成公有 B、全部变成保护
C、全部变成私有 ** D、仍然相应保持为公有和保护
4、建立包含有类对象成员的派生类对象时,自动调用构造函数的执行顺序依次为 (4) 的构造函数。
A、自己所属类、对象成员所属类、基类
B、对象成员所属类、基类、自己所属类
** C、基类、对象成员所属类、自己所属类
D、基类、自己所属类、对象成员所属类
5、派生类的对象对其基类中 (5) 可直接访问。
** A、公有继承的公有成员 B、公有继承的私有成员
C、公有继承的保护成员 D、私有继承的以有成员
6、设类B是基类A的派生类,并有语句:A aa, * pa=&aa; B bb, * pb=&bb; 则正确的语句是___(6)__ 。
A、pb=pa; B、bb=aa; **C、aa=bb; D、*pb=pa;
7、在公有派生情况下,有关派生类对象和基类对象的关系,不正确的叙述是 _ (7)__.
A、派生类的对象可以赋给基类的对象
B、派生类的对象可以初始化基类的引用
**C、派生类的对象可以直接访问基类中的成员
D、派生类的对象的地址可以赋给指向基类的指针
8、若类X和类Y的定义如下:
class X
{ int a,b;
public:
void fx ( );
};
class Y: public X
{ int c;
public:
void fy ( );
};
void Y::fy ( ) { c=ab; }
则上述代码中, (8) 是非法的语句。
A、void fx(); ** B、c=ab; C、void fy(); D、int c;
9、如果一个派生类的基类不止一个,则这种继承称为__(9)__。
A、单继承 B、虚继承 C、多态继承 ** D、多重继承
11、下面叙述不正确的是 (11) 。
A、派生类可以使用private派生
**B、基类的public成员在派生类中仍然是public
C、对基类成员的访问必须是无二义性的
D、赋值兼容原则也适合多重继承的组合
12、下面叙述不正确的是 (12) 。
**A、基类的protected成员在派生类中仍然是protected
B、基类的protected成员在public派生类中仍然是protected
C、基类的protected成员在private派生类中仍然是private
D、对基类成员的访问必须是无二义性的
13、下面叙述不正确的是 (13) 。
A、成员的访问能力在private派生类中和public派生类中仍是不同的
B、基类的private成员在public派生类中不可访问
C、赋值兼容规则不适合于多重继承的组合
D、public基类成员在protected派生中是protected
14、下面叙述正确的是 (14) 。
A、基类的对象可以赋给派生类
B、只要是基类的对象,都可以赋给由它派生的任一个派生类对象
C、只有该基类直接派生出来的类的对象才可以赋给该基类的对象
**D、公有派生类的对象可以赋给基类的对象
15以下程序的输出结果为是 (15) 。
#include
using namespace std;
class A
{ public:
int n;
};
class B:virtual public A{};
class C:virtual public A{};
class D:public B,public C
{ int getn() {return B::n; }
};
int main()
{ D d;
d.B::n=10;
d.C::n=20;
cout<<d.B::n<<“,”<<d.C::n<<endl;
return 0;
}
A、10,20 ** B、20,20 C、10,10 D、输出有二义性,不确定
多态性
10.2 典型例题分析与解答
例题1: 指出下列对定义重载函数的要求中,哪些是错误的提法。
A. 要求参数的个数不同。 B.要求参数中至少有一个类型不同。
C. 求函数的返回值不同。 D. 要求参数的个数相同时,参数类型不同。
答案:C
例题3: 下面关于友元的描述中,错误的是( )。
A. 友元函数可以访问该类的私有数据成员
B. 一个类的友元类中的成员函数都是这个类的友元函数
C. 友元可以提高程序的运行效率
D. 类与类之间的友元关系可以继承
答案:D
例题4: 下述静态成员的特性中,( )是错误的。
A. 静态成员函数不能利用this指针
B. 静态数据成员要在类体外进行初始化
C. 引用静态数据成员时,要在静态数据成员名前加<类名>和作用域运算符
D. 静态数据成员不是所有对象所共有的
答案:D
例题5: 关于虚函数的描述中,( )是正确的。
A. 虚函数是一个静态成员函数
B. 虚函数是一个非成员函数
C. 虚函数既可以在函数说明时定义,也可以在函数实现时定义
D. 派生类的虚函数与基类中对应的虚函数具有相同的参数个数和类型
答案:D
10.3 教材习题解答
1.选择题
(1)下列关于动态联编的描述中,错误的是()。
A.动态联编是以虚函数为基础
B.动态联编是运行时确定所调用的函数代码的
C.动态联编调用函数操作是指向对象的指针或对象引用
D.动态联编是在编译时确定操作函数的
答案:D
(2)关于虚函数的描述中,正确的是()。
A.虚函数是一个静态成员函数
B.虚函数是一个非成员函数
C.虚函数即可以在函数说明定义,也可以在函数实现时定义
D.派生类的虚函数与基类中对应的虚函数具有相同的参数个数和类型
答案:D
(3)下面4个选项中,( )是用来声明虚函数的。
A.virtual B.public C.using D.false
答案:A
(4)编译时的多态性可以通过使用( )获得。
A.虚函数和指针 B.重载函数和析构函数 C.虚函数和对象 D.虚函数和引用
答案:A
(5)关于纯虚函数和抽象类的描述中,错误的是( )。
A.纯虚函数是一种特殊的虚函数,它没有具体的实现
B.抽象类是指具体纯虚函数的类
C.一个基类中说明有纯虚函数,该基类派生类一定不再是抽象类
D.抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出
答案:B
(6)下列描述中,( )是抽象类的特征。
A.可以说明虚函数 B.可以进行构造函数重载 C.可以定义友元函数 D.不能说明其对象
答案:D
(7)以下( )成员函数表示虚函数。
A.virtual int vf(int); B.void vf(int)=0;
C.virtual void vf()=0; D.virtual void vf(int) { };
答案:D
(8)如果一个类至少有一个纯虚函数,那么就称该类为( A )。
A.抽象类 B.虚函数 C.派生类 D.以上都不对
答案:A
(9)要实现动态联编,必须通过( )调用虚函数。
A.对象指针 B.成员名限定 C.对象名 D.派生类名
答案:A
(10)下面描述中,正确的是(A )。
A.virtual可以用来声明虚函数
B.含有纯虚函数的类是不可以用来创建对象的,因为它是虚基类
C.即使基类的构造函数没有参数,派生类也必须建立构造函数
D.静态数据成员可以通过成员初始化列表来初始化
答案:A
3.选择题
3.1在C++中,要实现动态联编,必须使用(D)调用虚函数。
A.类名 B.派生类指针 C.对象名 D.基类指针
3.2下列函数 中,不能说明为虚函数的是©。
A.私有成员函数 B.公有成员函数 C.构造函数 D.析构函数
3.3在派生类中,重载一个虚函数时,要求函数名、参数的个数、参数的类型、参数的顺序和函数的返回值(A)。
A.相同 B.不同 C.相容 D.部分相同
3.4当一个类的某个函数被说明为virtual时,该函数在该类的所有派生类中(A)。
A.都是虚函数
B.只有被重新说明时才是虚函数
C.只有被重新说明为virtual时才是虚函数
D.都不是虚函数
3.5( C)是一个在基类中说明的虚函数,它在该基类中没有定义,但要求任何派生类都必须定义自己的版本。
A.虚析构函数 B.虚构造函数
C.纯虚函数 D.静态成员函数
3.6 以下基类中的成员函数,哪个表示纯虚函数(C)。
A.virtual void vf(int); B.void vf(int)=0;
C.virtual void vf( )=0; D.virtual void vf(int){ }
3.7下列描述中,(D)是抽象类的特性。
A.可以说明虚函数
B.可以进行构造函数重载
C.可以定义友元函数
D.不能定义其对象
3.8类B是类A的公有派生类,类A和类B中都定义了虚函数func( ),p是一个指向类A对象的指针,则p->A::func( )将(A)。
A.调用类A中的函数func( )
B.调用类B中的函数func( )
C.根据p所指的对象类型而确定调用类A中或类B中的函数func( )
D.既调用类A中函数,也调用类B中的函数
3.9类定义如下。
class A{
public:
virtual void func1( ){ }
void fun2( ){ }
};
class B:public A{
public:
void func1( ) {cout<<”class B func1”<<endl;}
virtual void func2( ) {cout<<”class B func2”<<endl;}
};
则下面正确的叙述是(A)
A.A::func2( )和B::func1( )都是虚函数
B.A::func2( )和B::func1( )都不是虚函数
C.B::func1( )是虚函数,而A::func2( )不是虚函数
D.B::func1( )不是虚函数,而A::func2( )是虚函数
3.10下列关于虚函数的说明中,正确的是( B)。
A.从虚基类继承的函数都是虚函数
B.虚函数不得是静态成员函数
C.只能通过指针或引用调用虚函数
D.抽象类中的成员函数都是虚函数
3. 选择题
3.1关于函数模板,描述错误的是(A )。
A.函数模板必须由程序员实例化为可执行的函数模板
B.函数模板的实例化由编译器实现
C.一个类定义中,只要有一个函数模板,则这个类是类模板
D.类模板的成员函数都是函数模板,类模板实例化后,成员函数也随之实例化
3.2下列的模板说明中,正确的是(D )。
A.template<typename T1,T2>
B.template<class T1,T2>
C.template<class T1,class T2>
D.template<typename T1,typename T2>
3.3 函数模板定义如下:
template
Max( T a, T b ,T &c){c=a+b;}
下列选项正确的是(B )。
A. int x, y; char z; B.double x, y, z;
Max(x, y, z); Max( x, y, z);
C.int x, y; float z; D.float x; double y, z;
Max( x, y, z); Max( x,y, z);
3.4 下列有关模板的描述错误的是(D)。
A. 模板把数据类型作为一个设计参数,称为参数化程序设计。
B. 使用时,模板参数与函数参数相同,是按位置而不是名称对应的。
C. 模板参数表中可以有类型参数和非类型参数。
D. 类模板与模板类是同一个概念。
3.5类模板的使用实际上是将类模板实例化成一个(C)。
A.函数 B.对象 C.类 D.抽象类
3.6类模板的模板参数(D)。
A.只能作为数据成员的类型 B.只可作为成员函数的返回类型
C.只可作为成员函数的参数类型 D.以上三种均可
3.7类模板的实例化(A)。
A.在编译时进行 B.属于动态联编
C.在运行时进行 D.在连接时进行
3.8以下类模板定义正确的为(A)。
A.template<class T,int i=0> B.template<class T,class int i>
C.template<class T,typename T> D.template<class T1,T2>
C++期末考试复习题
一、选择题
4. 在声明类时,下面的说法正确的是( C )。
A.可以在类的声明中给数据成员赋初值 B.数据成员的数据类型可以是register
C.private、public、protected可以按任意顺序出现
D.没有用 private、public、protected定义的数据成员是公有成员
5. 在一个类的定义中,包含有( C )成员的定义。
A. 数据 B. 函数 C. 数据和函数 D. 数据或函数
6. 假定AA为一个类,int a()为该类的一个成员函数,若该成员函数在类定义体外定义,则函数头为( A )。
A. int AA::a() B. int AA:a() C. AA::a() D. AA::int a()
7. 假定AA为一个类,a为该类公有的数据成员,px为指向该类对象的一个指针,则访问px所指对象中数据成员a的格式为( C )。
A. px(a) B. px[a] C. px->a D. px.a
8. 下列关于运算符new的描述中,错误的是( D )。
A.它可以创建对象或变量 B.它可以创建对象数组或一般类型数组
C.用它创建对象或对象数组时要调用相应的构造函数 D.用它创建的对象可以不用delete运算符释放
9. 在下面有关析构函数特征的描述中,正确的是( A )。
A.一个类中可以定义多个析构函数 B.析构函数名与类名完全相同
C.析构函数不能指定返回类型 D.析构函数可以由一个或多个参数
10. 构造函数是在( B )时被执行的。
A.程序编译 B. 创建对象 C. 创建类 D. 程序装入内存
11. 友元的作用之一是( A )。
A.提高程序的运行效率 B.加强类的封装性
C.实现数据的隐藏性 D.增加成员函数的种类
12. 设置虚基类的目的是( B )。
A.简化程序 B.消除二义性 C. 提高运行效率 D.减少目标代码
13. 重载函数在调用时选择的依据中,( B )是错误的。
A. 函数名字 B.函数的返回类型 C.参数个数 D.参数的类型
14. 已知:int fun (int &a),m=10;下列调用fum()函数的语句中,正确的是( C )。
A.fun(&m); B.fun (m*2); C.fun (m); D.fun (m++);
15. 下列各种类中,不能定义对象的类是( B )。
A.派生类 B.抽象类 C.嵌套类 D.虚基类
16. 类中定义的成员默认为( A )访问属性。
A. public B. private C. protected D. friend
17. 静态成员函数对类的数据成员访问( B )。
A. 是不允许的 B. 只允许是静态数据成员
C. 只允许是非静态数据成员 D. 可允许是静态数据成员或非静态数据成员
18. 在下列语句中,将函数int f_sum(int x,int y)正确重载的是( A )。
A.float f_sum(int x,int y) B.int f_sum(int a,int b)
C.int f_sum(int x) D.float f_sum(int a,int b)
19. 下列各语句是输出字符’A’的,其中错误语句是( B )。
A.cout<<‘A’; B.cout.put(‘A’); C.char ch=‘A’;cout<<ch; D.cout<<put(‘A’);
20. 当将一个类A或函数f()说明为另一个类B的友元后,类A或函数f()能够直接访问类B的( D )。
A. 只能是公有成员 B. 只能是保护成员
C. 只能是除私有成员之外的任何成员 D. 具有任何权限的成员
21. C++语言程序中进行文件操作时应包含的头文件是( A )。
A.fstream.h B.math.h C.stdlib.h D.strstrea.h
22. 在C++程序中使用的cin标识符是系统类库中定义的( A )类中的一个对象。
A. istream B. ostream C. iostream D. fstream
23. 如果表达式a+b中的“+”是作为友元函数重载的运算符,若采用运算符函数调用格式,则可表示为( C )。
A. a.operator+(b) B. b.operator+(a) C. operator+(a,b) D. operator(a+b)
24. 假定一个类对象数组为A[n],当离开它定义的作用域时,系统自动调用该类析构函数的次数为( C )。
A. 0 B. 1 C. n D. n-1
25. 在C++程序中使用的cout标识符是系统类库中定义的
( B )类中的一个对象。
A. istream B. ostream C. iostream D. fstream
三、填空题
1.写出以下程序运行后每一行的显示结果。
class Base{
int x;
public:
Base(int i){ x=i; cout<<“Base:”<<x<<endl;}
virtual Base(){cout<<"Base"<<endl;}
};
class Drived: public Base{
int y;
public:
Drived(int i,int j):Base(i){ y=j; cout<<“Drived :”<<y<<endl;}
Drived(){cout<<"Drived"<<endl;}
};
int main(){
Base *pb=new Base(5); delete pb;
pb=new Drived(2,8); delete pb;
return 0;
}
答案:Base:5 //1分
~Base //1分
Base:2 //2分
Drived :8 //2分
~Drived //2分
~Base //2分
2.阅读以下程序:
#include
using namespace std;
class A{
int a,b;
public:
A(int i,int j){a=i;b=j;}
void move(int x,int y){a+=x;b+=y;}
void disp(){cout<<“(”<<a<<“,”<<b<<“)”<<endl;}
};
class B:public A{
int x,y;
public:
B(int i,int j,int k,int l): {}
void disp(){cout<<x<<“,”<<y<<endl;}
void fun1(){move(1,2);}
void fun2(){A::disp();}
};
int main(){
A aa(11,12);
aa.disp();
B bb(13,14,15,16);
bb.fun1();
bb.A::disp();
bb.disp();
bb.fun2();
return 0;
}
(1)将程序中划线处补充完整,要求从基类继承的成员a、b的初始值分别为i和j, x初始化值为k, y初始化值为l。
(2)写出程序运行后每一行的显示结果。
答案(1) A(i,j),x(k),y(l) //2分
(2) (11,12) //2分
(14,16) //2分
15,16 //2分
(14,16) //2分
例题11:分析下列程序的输出结果。
#include <iostream.h>
class A{
public:
A() { cout<<“A’s cons.”<<endl; }
virtual ~A() { cout<<“A’s des.”<<endl; }
virtual void f() { cout<<“A’s f().”<<endl; }
void g() { f(); }
};
class B : public A{
public:
B() { f(); cout<<“B’s cons.”<<endl; }
~B() { cout<<“B’s des.”<<endl; }
};
class C : public B{
public:
C() { cout<<“C’s cons.”<<endl; }
~C() { cout<<“C’s des.”<<endl; }
void f() { cout<<“C’s f().”<<endl; }
};
void main()
{ A *a=new C;
a->g();
delete a;
}
运行结果:
A’s cons.
A’s f().
B’s cons.
C’s cons.
C’s f().
C’s des.
B’s des.
A’s des.
4.写出下列程序运行结果
4.1#include
using namespace std;
class A {
public:
virtual void func( ) {cout<<”func in class A”<<endl;}
};
class B{
public:
virtual void func( ) {cout<<”func in class B”<<endl;}
};
class C:public A,public B{
public:
void func( ) {cout<<”func in class C”<<endl:}
};
int main( ){
C c;
A& pa=c;
B& pb=c;
C& pc=c;
pa.func( );
pb.func( );
pc.func( );
}
func in class C
func in class C
func in class C
4.2#include
using namespace std;
class A{
public:
virtual ~A( ){
cout<<”A::~A( ) called “<<endl; }
};
class B:public A{
char *buf;
public:
B(int i) { buf=new char[i]; }
virtual ~B( ){
delete []buf;
cout<<”B::~B( ) called”<<endl;
}
};
void fun(A *a) {
delete a;
}
int main( )
{ A *a=new B(10);
fun(a);
}
B::~B( ) called
A::~A( ) called>
2.什么叫做多态性?在C++语言中是如何实现多态的?
答:多态是指同样的消息被不同类型的对象接收时导致完全不同的行为,是对类的特定成员函数的再抽象.c十+支持的多态有多种类型.重载(包括函数重载和运算符重载)和虚函数是其中主要的方式.
3.什么叫做抽象类?抽象类有何作用?抽象类的派生类是否一定要给出纯虚函数?
答:带有纯虚函数的类是抽象类.抽象类的主要作用是通过它为一个类族建立一个公共的接口.使它们能够更有效地发挥多态特性。抽象类声明了一组派生类共同操作接口的通用语义.面接口的完整实现,即纯虚函数的函数体,要由派生类自己给出.但抽象类的派生类并非一定要给出纯虚函数的实现.如果派生类没有给出纯虚函数的实现,这个派生类仍然是一个抽象类.
4.声明一个参数为整型、无返回值、名为fun1的虚函数。
答: virtual void fnl(int);
5.在C++语言中,能否声明虚构造函数?为什么?能否声明虚析构函数?有何用途?
答:在C+±中不能声明虚构造函数.多态是不同的对象对同一消息有不同的行为特性.虚函数作为运行过程中多态的基础,主要是针对对象的,面构造函数是在对盘产生之前运行的,因此虚构造函数是没有童义的.
在C++中可以声明虚析构函数.析构函数的功能是在该类对象消亡之前进行一些必要的清理工作,如果一个类的析构函数是虚函数,那么,由它派生而来的所有子类的析构函数也是虚函数.析构函数设置为虚函数之后,在使用指针引用时可以动态联编,实理运行时的多态,保证使用基类的指针就能够谓用适当的析构函数指针对不同的对象进行清理工作.
1.概念填空题
- 在下面一段类定义中, Derived类是由直接基类Base 1和Base 2所派生的,Derived类包含有两个间接基类BaseBase,在初始化函数Init中,需要把x1和x2的值分别赋给属于基类Base1的x成员和属于基类Base2的x成员。
class BaseBase {
protected:
int x;
public:
BaseBase(){ x = 1;}
};
class Base1: public BaseBase {
public:
Base1(){}
};
class Base2: public BaseBase {
public:
Base2(){}
};
class Derived: (1) public Base1 , (2) public Base2
{
public:
Derived() {}
void Init(int x1, int x2) {
(3) Base1::x=x1 ;
_(4)__ Base2::x=x2 _;
}
(5) void output() {cout<<Base1::x<<' '<<Base2::x<<endl;}
};
四、根据程序试写出运行结果
1.
#include <iostream.h>
void main( )
{
int i, j;
int *p1, *p2;
p1=&i; p2=&j ;
i=3; j=6;
cout<<"i="<<i<<" j="<<j<<endl;
cout<<"*p1="<<*p1<<" *p2="<<*p2<<endl;
*p1=5; *p2=8;
cout<<"i="<<i<<" j="<<j<<endl;
cout<<"*p1="<<*p1<<" *p2="<<*p2<<endl;
}
2.
#include<iostream.h>
#include<string.h>
class CD {
char* a;
int b;
public:
void Init(char* aa, int bb)
{
a=new char[strlen(aa)+1];
strcpy(a,aa);
b=bb;
}
char* Geta() {return a;}
int Getb() {return b;}
void Output() {cout<<a<<' '<<b<<endl;}
};
void main()
{
CD dx,dy;
char a[20];
dx.Init("abcdef",30);
strcpy(a,dx.Geta());
strcat(a,"xyz");
dy.Init(a,dx.Getb()+20);
dx.Output();
dy.Output();
}
#include<iostream.h>
class A {
int a[10]; int n;
public:
A(int aa[], int nn): n(nn) {
for(int i=0; i<n; i++) a[i]=aa[i];
}
int Get(int i) {return a[i];}
int SumA(int n) {
int s=0;
for(int j=0; j<n; j++) s+=a[j];
return s;
}
};
void main() {
int a[]={2,5,8,10,15,20};
A x(a,4);
A y(a,6);
int d=1;
for(int i=0; i<4; i++) d*=x.Get(i);
int f=y.SumA(5);
cout<<"d="<<d<<endl;
cout<<"f="<<f<<endl;
}
#include<iostream.h>
class circle {
protected:
int r;
public:
void setr(int x){ r=x; }
virtual void show( )=0;
};
class area:public circle{
public:
void show( )
{ cout<<"这个圆的面积是:"<<3.14*r*r<<endl;} };
class perimeter:public circle{
public:
void show( )
{ cout<<"这个圆的周长是: "<<2*3.14*r<<endl;} };
void main( )
{ circle *ptr;
area ob1;
perimeter ob2;
ob1.setr(10);
ob2.setr(10);
ptr=&ob1; ptr->show();
ptr=&ob2; ptr->show();
}
#include<iostream.h>
class A {
public:
A( ) { cout << "A"; }
};
class B {
public:
B( ) { cout <<"B"; }
};
class C: public A {
public:
C( ) { cout << "C"; }
private:
B b;
};
int main ( )
{
C obj;
return 0;
}
#include<iostream.h>
class small_cat{
double weight; //普通数据成员,表示一只小猫的重量
static double total_weight;//静态数据成员,用来累计小猫的重量
static double total_number; //静态数据成员,用来累计小猫的只数
public:
small_cat(double w) //构造函数
{ weight=w;
total_weight+=w; //累加小猫的重量
total_number++; } //累加小猫的只数
void display()
{ cout<<"这只小猫的重量是 "<<weight<<"千克\n"; }
static void total_disp()
{ cout<<total_number <<" 只的小猫的总重量是 ";
cout<<total_weight <<"千克"<<endl; }
};
double small_cat::total_weight=0; //静态数据成员初始化
double small_cat::total_number=0; //静态数据成员初始化
int main()
{ small_cat w1(0.5),w2(0.6),w3(0.4);
w1.display(); //调用普通成员函数,显示第1只小猫的重量
w2.display(); //调用普通成员函数,显示第2只小猫的重量
w3.display(); //调用普通成员函数,显示第3只小猫的重量
small_cat::total_disp(); //调用静态成员函数
return 0; } //显示小猫的只数和总重量
四、程序题
10.声明一个Shape抽象类,在此基础上派生出Rectangle和Circle类,二者都有GetArea( )函数计算对象的面积,GetPerim( )函数计算对象的周长。
解答:
#include<iostream.h>
#include<math.h>
class shape
{ public:
virtual void getarea()=0;
virtual void getperim()=0;
};
class rectangle:public shape
{ int a,b,c;
double s,p;
public:
rectangle(int a1,int b1,int c1) {a=a1;b=b1;c=c1;}
void getperim()
{ p=a+b+c; cout<<"周长 "<<p<<endl;}
void getarea()
{ p=(a+b+c)/2.0;
s=sqrt(p*(p-a)*(p-b)*(p-c));
cout<<"面积 "<<s<<endl;
}
};
class circle :public shape
{ float r,s,p;
public:
circle(float r1) {r=r1;}
void getperim() { p=2*r*3.1415926;cout<<"周长 "<<p<<endl;}
void getarea() { s=r*r*3.1415926; cout<<"面积 "<<s<<endl;}
};
void show(shape *p)
{ p->getarea();
p->getperim();
}
void main()
{ shape *p;
rectangle a(3,4,5);
circle b(10);
p=&a; show(p);
p=&b; show(p);
}
- 定义时钟类Clock,包含时、分、秒三个整型数据成员,成员函数有:形参带默认值的构造函数、设置时间的函数、显示时间的函数。定义时钟类Clock的友元类PlaneTrip,组合了Clock类的2个对象,表示某航班的出发和到达时间,形式如下:
class PlaneTrip{
string no; //航班号
Clock departure, arrival; //出发、到达时间
public:
PlaneTrip(string,Clock,Clock);
Clock FlightTime(); //飞行时间
};
(1)完成Clock类定义(包括程序开头的文件包含命令等)(6分)
#include<iostream>
using namespace std;
class Clock{
public:
Clock(int h=0, int m=0, int s=0); //1分
void ShowTime();
void SetTime(int, int, int);
private:
int Hour,Minute,Second; //1分
friend class PlaneTrip; //1分
};
void Clock::SetTime(int h, int m, int s){ //1分
Hour= h<0 || h > 23 ? 0: h ;
Minute= m<0 || m> 59 ? 0: m;
Second= s<0 || s> 59 ? 0: s;
}//可以不做数据合法性检查
Clock::Clock(int h, int m, int s){
SetTime(h, m, s); //1分
}
void Clock::ShowTime(){ //1分
cout<<Hour<<":"<< Minute <<":"<< Second<<endl;
}
(2)完成PlaneTrip类定义(5分)
class PlaneTrip{
string no; //航班号
Clock departure, arrival; //出发、到达时间
public:
PlaneTrip(string,Clock,Clock);
Clock FlightTime(); //飞行时间
};
PlaneTrip::PlaneTrip(string number,Clock d,Clock a):departure(d),arrival(a){ //1分
no=number;
}
Clock PlaneTrip::FlightTime(){ //1分
Clock dif;
int carry=0;
(dif.Second=arrival.Second-departure.Second)>=0 ? carry=0 :(dif.Second+=60,carry=1);
(dif.Minute=arrival.Minute-departure.Minute-carry)>=0 ? carry=0 :(dif.Minute+=60,carry=1);
(dif.Hour=arrival.Hour-departure.Hour-carry)>=0 ? carry=0 :dif.Hour+=24; //2分
return dif; //1分
}
(3)主函数中输入飞机航班号,出发和到达时间,计算飞行时间并输出结果。(4分)
int main(){
string number;
Clock ft;
int h,m,s;
cout<<"输入航班号:"<<endl;
cin>>number;
cout<<"输入出发时间:"<<endl;
cin>>h>>m>>s;
Clock st(h,m,s); //1分
cout<<"输入到达时间:"<<endl;
cin>>h>>m>>s;
Clock en(h,m,s);
PlaneTrip p(number,st,en); //1分
ft=p.FlightTime(); //1分
cout<<"飞行时间:"<<endl;
ft.ShowTime(); //1分
return 0;
}
2.图书类Book定义如下:
#include<iostream>
#include<cstring>
#include<fstream>
using namespace std;
class Book{
int No;// No存放书号
char * bname; //字符指针,指向动态申请的存放书名的字符串。
public:
Book (int n=0, const char* name=NULL);//构造函数
~ Book (){ if (bname) delete []bname;}//析构函数
Book (const Book &);//复制构造函数
Book & operator=( Book &);//=运算符重载函数
bool operator<( Book &); //<运算符重载函数(按书号大小比较)
friend ostream& operator<<(ostream &, Book &);
};
(1)在类外完成Book类的构造函数定义(5分)
Book::Book(int n,const char* name){ //1分
No=n; //1分
if(name) { //1分
bname=new char[strlen(name)+1]; //1分
strcpy(bname,name); //1分
}
else bname=NULL;
}
(2)在类外完成Book类的复制构造函数定义(5分)
Book::Book(const Book& a){ //1分
No=a.No; //1分
if(a.bname){ //1分
bname=new char[strlen(a.bname)+1]; //1分
strcpy(bname,a.bname); //1分
}
else bname=NULL;
}
(3)在类外完成赋值运算符重载函数的定义(3分)
Book& Book::operator=(Book& s){ //1分
if(this==&s) return *this;
No=s.No;
if(bname) delete []bname; //1分
if(s.bname){
bname=new char[strlen(s.bname)+1];
strcpy(bname,s.bname);
}
else bname=NULL;
return *this; //1分
}
(4)在类外完成<运算符重载函数的定义(1分)
bool Book::operator<( Book & b){
return No<b.No; //1分
}
(5)完成插入运算符重载函数定义(2分)
ostream& operator<<(ostream& out, Book& s){
out<<s.No<<"\t"<<s.bname; //1分
return out; //1分
}
(6)设计函数模板templatevoid sort(T a[],int n),实现对一维数组元素的升序排序。(4分)
template<class T>void sort(T a[],int n) //1分
{
int i,j,k;
T t; //1分
for(i=0;i<n-1;i++)
{ k=i;
for(j=i+1;j<n;j++)
if(a[j]<a[k]) k=j; //1分
if(k!=i){
t=a[i]; //1分
a[i]=a[k];
a[k]=t;
}
}
}
(7)定义主函数,主函数中定义Book类对象数组,共5个元素,并初始化,利用函数模板对其排序,将排序结果写入文本文件book.txt中。(5分)
int main(){
Book bo[5]={Book(105,"name1"),Book(43,"name2"),Book(98,"name3"),Book(66,"name4"),Book(57,"name5")}; //1分
int i;
ofstream ofile("book.txt"); //1分
sort<Book>(bo,5); //1分
for(i=0;i<5;i++){
ofile<<bo[i]<<endl; //1分
cout<<bo[i]<<endl;
}
ofile.close(); //1分
return 0;
}
3.设计如下类:
3.(1)Student抽象类。Student有2个纯虚函数virtual double pay()和 virtual void show(),没有数据成员。(4分)
#include<iostream>
using namespace std;
class Student{ //1分
public: //1分
virtual double pay()=0; //1分
virtual void show()=0; //1分
};
(2)Student公有派生研究生类Graduate。Graduate新增保护数据成员int classHour(课时数)和double rem(每学时课酬金),定义Graduate类的构造函数,并实现基类中的虚函数,pay函数计算总收入,show函数显示数据成员值。(5分)
class Graduate:public Student{ //1分
protected:
int classHour;
double rem; //1分
public:
Graduate(int hour=0,double w=0){ //1分
classHour = hour;
rem=w;
}
double pay(){return classHour*rem;} //1分
void show(){cout<<"课时:"<<classHour<<"\t"<<"每学时课酬金:"<<rem<<endl;} //1分
};
(3)Graduate公有派生博士类Doctor。Doctor新增数据成员double salary(固定月薪),定义Doctor类的构造函数,并实现基类中的虚函数,pay函数计算总收入为固定月薪加上课酬金,show函数显示数据成员值。(6分)
class Doctor:public Graduate{ //1分
double salary; //1分
public:
Doctor(double s=0,int c=0,double r=0) //1分
:Graduate(c,r) //1分
{salary=s ;}
double pay(){
return salary+classHour*rem;
} //1分
void show(){
cout<<"固定月薪:"<<salary<<"\t"
<<"课时:"<<classHour<<"\t"<<"每学时课酬金:"<<rem<<endl;
} //1分
};
(4)定义主函数,其中建立Graduate类和Doctor类对象,定义抽象类指针,用抽象类指针调用Graduate类和Doctor类对象的虚函数pay ()和show(),并显示结果。(5分)
int main(){
Graduate g(80,10); //1分
Doctor d(2000,100,20); //1分
Student * p[2]={&g,&d}; //1分
for(int i=0;i<2;i++){
p[i]->show(); //1分
cout<<"总收入:"<<p[i]->pay()<<endl;//1分
}
return 0;
}
4.编程题
4.1设计一个函数模板,其中包括数据成员T a[n]以及对其进行排序的成员函数 sort( ),模板参数T可实例化成字符串。
#include <iostream>
#include <string>
using namespace std;
template<typename T>void Sort(T* a,int n){
int i,j;
T t;
for(i=0;i<n-1;i++)
for(j=0;j<n-i-1;j++)
if (a[j]>a[j+1])
{ t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
template<typename T>void Print(T* a,int n){
int i;
for(i=0;i<n;i++)
cout<<a[i]<<" ";
cout<<endl;
}
int main(){
string Str[10]={"Zhang","Li","Wang","Qian","Zhao","Wu","Xu","Tang","Shen","Liang"};
int Int[8]={20,12,0,-5,9,-18,6,11};
double Dou[7]={3.07,8.12,-0.45,6,10,-9,7.29};
Sort<string>(Str,10);
Sort<int>(Int,8);
Sort<double>(Dou,7);
Print(Str,10);
Print(Int,8);
Print(Dou,7);
return 0;
}
4.2设计一个类模板,其中包括数据成员T a[n]以及在其中进行查找数据元素的函数int search(T)模板参数 T可实例化成字符串。
#include <iostream>
using namespace std;
template<typename T,int n>class A{
int size;
T* element;
public:
A();
~A();
int Search(T);
void SetElement(int index,const T& value);
};
template<typename T,int n>A<T,n>::A(){
size=n>1? n:1;
element=new T[size];
}
template<typename T,int n>A<T,n>::~A(){
delete [] element;
}
template<typename T,int n>int A<T,n>::Search(T t){
int i;
for(i=0;i<size;i++)
if(element[i]==t)
return i;
return -1;
}
template<typename T,int n>void A<T,n>::SetElement(int index,const T& value){
element[index]=value;
}
int main(){
A<int,5> intAry; //用int实例化,建立模板类对象
A<double,10> douAry;//用double实例化,建立模板类对象
int i;
for(i=0;i<5;i++)
intAry.SetElement(i,i+3);
for(i=0;i<10;i++)
douAry.SetElement(i,(i+i)*0.35);
i=intAry.Search(7);
if(i>=0)cout<<i<<endl;
i=douAry.Search(0.7);
if(i>=0)cout<<i<<endl;
return 0;
}
4.3设计一个单向链表类模板,节点数据域中数据从小到大排列,并设计插入、删除节点的成员函数。
#include<iostream>
using namespace std;
template<typename T>class List;
template<typename T>class Node{
T info; //数据域
Node<T> *link; //指针域
public:
Node(); //生成头结点的构造函数
Node(const T & data);//生成一般结点的构造函数
friend class List<T>;
};
template <typename T> Node<T>::Node(){link=NULL;}
template <typename T> Node<T>::Node(const T & data){
info=data;
link=NULL;
}
//定义链表类
template<typename T>class List{
Node<T> *head; //链表头指针和尾指针
public:
List(); //构造函数,生成头结点(空链表)
~List(); //析构函数
void MakeEmpty(); //清空一个链表,只余表头结点
Node<T>* Find(T data); //搜索数据域与data相同的结点,返回该结点的地址
void PrintList(); //打印链表的数据域
void InsertOrder(Node<T> *p); //按升序生成链表
Node<T>* CreatNode(T data); //创建一个结点(孤立结点)
Node<T>* DeleteNode(Node<T>* p); //删除指定结点
};
template<typename T>List<T>::List(){
head=new Node<T>(-9999);//头结点,最小的数据从小到大插入
}
template<typename T>List<T>::~List(){
MakeEmpty();
delete head;
}
template<typename T>void List<T>::MakeEmpty(){
Node<T> *tempP;
while(head->link!=NULL){
tempP=head->link;
head->link=tempP->link; //把头结点后的第一个节点从链中脱离
delete tempP; //删除(释放)脱离下来的结点
}
}
template<typename T> Node<T>* List<T>::Find(T data){
Node<T> *tempP=head->link;
while(tempP!=NULL && tempP->info!=data) tempP=tempP->link;
return tempP; //搜索成功返回该结点地址,不成功返回NULL
}
template<typename T>void List<T>::PrintList(){
Node<T>* tempP=head->link;
while(tempP!=NULL){
cout<<tempP->info<<'\t';
tempP=tempP->link;
}
cout<<endl;
}
template<typename T>void List<T>::InsertOrder(Node<T> *p){
Node<T> *tempP=head,*tempQ=head; //tempQ指向tempP前面的一个节点
while(tempP!=NULL){
if(p->info<tempP->info)break; //找第一个比插入结点大的结点,由tempP指向
tempQ=tempP;
tempP=tempP->link;
}
p->link=tempP;
tempQ->link=p;
}
template<typename T>Node<T>* List<T>::CreatNode(T data){//建立新节点
Node<T>*tempP=new Node<T>(data);
return tempP;
}
template<typename T>Node<T>* List<T>::DeleteNode(Node<T>* p){
Node<T>* tempP=head->link,*tempQ=head,*tempC;
while(tempP!=NULL && tempP!=p){
tempQ=tempP;
tempP=tempP->link;
}
tempC=tempP;
tempQ->link=tempP->link;
return tempC;
}
int main(){
Node<int> * P1;
List<int> list1;
int a[10]={20,12,0,-5,9,-18,6,11,5,3},i,j;
for(i=0;i<10;i++){
P1=list1.CreatNode(a[i]);
list1.InsertOrder(P1);
}
list1.PrintList();
cout<<"请输入一个要求删除的整数"<<endl;
cin>>j;
P1=list1.Find(j);
if(P1!=NULL){
P1=list1.DeleteNode(P1);
delete P1;
list1.PrintList();
}
else cout<<"未找到"<<endl;
cout<<"请输入一个要求插入的整数"<<endl;
cin>>j;
P1=list1.CreatNode(j);
list1.InsertOrder(P1);
list1.PrintList();
list1.MakeEmpty();//清空list1
list1.PrintList();
return 0;
}
五、编程题
- 编程求圆、圆内接正方形和圈外切正方形的面积和周长。要求使用抽象类。
解:
#include <iostream.h>
const double PI=3.1415;
class Shape
{
public:
Shape(double i)
{ r=i; }
virtual void Area()=0;
virtual void Perimeter()=0;
protected:
double r;
};
class Circle:public Shape
{
public:
Circle(double i):Shape(i)
{ }
void Area()
{ cout<<"圆的面积是 "<<PI*r*r<<endl; }
void Perimeter()
{ cout<<"圆的周长是 "<<2*PI*r<<endl; }
};
class In_Square:public Shape
{
public:
In_Square(double i):Shape(i)
{ }
void Area()
{ cout<<"圆内接正方形的面积是 "<<2*r*r<<endl; }
void Perimeter()
{ cout<<"圆内接正方形的周长是 "<<4*1.414*r<<endl; }
};
class Ex_Square:public Shape
{
public:
Ex_Square(double i):Shape(i)
{ }
void Area()
{ cout<<"圆外切正方形的面积是 "<<4*r*r<<endl; }
void Perimeter()
{ cout<<"圆外切正方形的周长是 "<<8*r<<endl; }
};
void main()
{
Shape *ps;
ps=new Circle(8);
ps->Area();
ps->Perimeter();
ps=new In_Square(8);
ps->Area();
ps->Perimeter();
ps=new Ex_Square(8);
ps->Area();
ps->Perimeter();
delete ps;
}