中南大学考试试卷
中南大学考试试卷
一、选择题(单选)(每空1分,共15分)
1、系统在调用重载函数时往往根据一些条件确定哪个重载函数被调用,在下列选项中,不能作为依据的是( )。
A.函数的返回值类型 B.参数的类型 C.函数名称 D.参数个数
2、在C++中,用于实现动态多态性的是( )。
A.内联函数 B.重载函数 C.模板函数 D.虚函数
3、预处理命令在程序中都是以( )符号开头的。
A. * B. # C. & D. @
4、下列运算符中,( )运算符在C++中不能被重载。
A.&& B.[] C.:: D.new
5、模板的使用实际上是将类模板实例化成一个( )。
A.函数 B.对象 C.类 D.抽象类
6、要求通过函数来实现一种不太复杂的功能,并且要求加快执行速度,选用( )。
A. 内联函数 B. 重载函数 C. 递归调用 D. 嵌套调用
7、已知:print( )函数是一个类的常成员函数,它无返回值,下列表示中,( )是正确的。
A. void print( ) const; B. const void print( );
C. void const print( ); D. void print(const);
8、下面对模板的声明,正确的是( )。
A. template
C. template<class T1, class T2> D. template<class T1; class T2>
9、已知X类,则当程序执行到语句X array[3];时,调用了( )次构造函数。
A.0 B.1 C.2 D.3
10、假定TT为一个类,则该类的拷贝构造函数的声明语句为( )。
A.TT (TT x) B.TT& (TT x) C.TT (TT &x) D.TT (TT *x)
11、下列语句中,将函数int sum(int x, int y)正确重载的是( )。
A. float sum(int x, int y); B. int sum(int a, int b);
C. float sum(float x, float y); D. double sum(int y, int x);
12、下面( )的叙述不符合赋值兼容规则。
A. 派生类对象可以赋值给基类对象 B. 基类对象可以赋值给派生类对象
C. 派生类对象可以初始化基类对象 D. 派生类对象的地址可以赋值给指向基类指针
13、已知:int m=10; 下列表示引用的方法中,( )是正确的。
A.int &x=m; B.int &y=10; C.int &z; D.float &t=&m;
14、不能说明为虚函数的是( )。
A.析构函数 B.构造函数 C.类的成员函数 D.以上都不对
15、存储以下数据,占用存储字节最多的是( ) 。
A. 0 B. ‘0’ C. “0” D. 0.0
解释:
1、系统在调用重载函数时往往根据一些条件确定哪个重载函数被调用,在下列选项中,不能作为依据的是(A)。
解释:函数重载的依据是函数名称相同但参数列表不同(参数的类型、参数的个数)。函数的返回值类型不能作为区分重载函数的依据。
2、在C++中,用于实现动态多态性的是(D)。
解释:动态多态性是通过虚函数(virtual function)实现的。在运行时根据实际对象的类型调用相应的函数。
3、预处理命令在程序中都是以(B)符号开头的。
解释:C++中的预处理命令以#符号开头,例如 #include, #define。
4、下列运算符中,(C)运算符在C++中不能被重载。
解释::: 是作用域解析运算符,C++规定该运算符不能被重载。
5、模板的使用实际上是将类模板实例化成一个(C)。
解释:模板实例化后会生成具体的类,模板的作用是为泛型编程提供支持。
6、要求通过函数来实现一种不太复杂的功能,并且要求加快执行速度,选用(A)。
解释:内联函数在编译时展开,避免了函数调用的开销,从而加快执行速度。
7、已知:print( )函数是一个类的常成员函数,它无返回值,下列表示中,(A)是正确的。
解释:常成员函数在函数声明后加 const,表示该函数不会修改类的成员变量。
8、下面对模板的声明,正确的是(C)。
解释:模板声明的正确语法是template<class T1, class T2>,表示定义了两个类型参数。
9、已知X类,则当程序执行到语句X array[3];时,调用了(D)次构造函数。
解释:定义一个包含3个对象的数组时,会调用3次构造函数来初始化每个对象。
10、假定TT为一个类,则该类的拷贝构造函数的声明语句为(C)。
解释:拷贝构造函数的参数是该类对象的引用,声明为TT(const TT &x)。
11、下列语句中,将函数int sum(int x, int y)正确重载的是(C)。
解释:重载函数必须参数列表不同,float sum(float x, float y)与原函数参数类型不同,构成重载。
12、下面(B)的叙述不符合赋值兼容规则。
解释:基类对象不能赋值给派生类对象,因为基类对象可能缺少派生类对象所需的特性或成员。
13、已知:int m=10; 下列表示引用的方法中,(A)是正确的。
解释:int &x=m; 正确,表示x是m的引用。其他选项要么语法错误,要么类型不兼容。
14、不能说明为虚函数的是(B)。
解释:构造函数不能是虚函数,因为在对象创建之前不可能有虚函数的多态性行为。
15、存储以下数据,占用存储字节最多的是(D)。
解释:0.0 是双精度浮点数,占用8个字节。’0’ 是字符,占用1个字节。“0” 是字符串,占用2个字节(包括结束符)。0 是整型,占用4个字节。
二、填空题(每空1分,共15分)
1. 面向对象程序设计有4个主要特点: (1) 、 (2) 、(3) 、 (4) 。
2. 如果只想保留公共基类的一个复制,就必须使用关键字 (5) 把这个公共基类声明为虚基类。
3. 后置自增运算符“++”重载为类的成员函数(设类名为A)的形式为: (6) 。
4. 若要把void fun(A &a)定义为类A的友元函数,则应在类定义中加入语句 (7) 。
5. 在C++中,三种继承方式的说明符号为 (8) 、 (9) 、 (10) ,如果不加说明,则默认的继承方式为 (11) 。
6. 程序的三种基本的控制结构是: 顺序结构、(12) 和 (13) 。
7. 一个C++程序的开发步骤通常包括编辑、 (14) 、 (15)、运行和调试。
面向对象程序设计有4个主要特点: (1) 抽象、 (2) 封装、 (3) 继承、 (4) 多态性。
如果只想保留公共基类的一个复制,就必须使用关键字 (5) virtual 把这个公共基类声明为虚基类。
后置自增运算符“++”重载为类的成员函数(设类名为A)的形式为: (6) A operator++(int)。
若要把void fun(A &a)定义为类A的友元函数,则应在类定义中加入语句 (7) friend void fun(A &a)。
在C++中,三种继承方式的说明符号为 (8) public、 (9) private、 (10) protected,如果不加说明,则默认的继承方式为 (11) private。
程序的三种基本的控制结构是: 顺序结构、 (12) 选择结构 和 (13) 循环结构。
一个C++程序的开发步骤通常包括编辑、 (14) 编译、 (15) 链接、运行和调试。
三、判断题(每小题1分,共15分)
1. 友元函数说明在类体内,它是一种成员函数。
2. 构造函数的名字必须与类名相同,其返回类型缺省为void类型。
3. 运算符重载以后,其优先级和结合性都不能改变。
4. 在类Time中的析构函数可以声明为:void ~Time(int) 。
5. 纯虚函数是在基类中说明的虚函数,它在该基类中没有定义具体的操作内容。
6. 在C++中,函数名实际上是一个指针,它指向函数的入口。
7. 常对象只能调用它的常成员函数, 而不能调用普通的成员函数。
8. 类静态成员数据为该类所有对象共享,在该类对象被撤销时,静态成员并不撤销。
9. 在声明一个类时,必须同时声明类的数据成员和成员函数。
10. 析构函数的作用是当对象不用时,删除对象。
11. 已知:int a=5,b=10; 表达式++a+b++有二义性。
12. 在传值调用中,要求实参和形参的类型完全一致并且个数相等。
13. const char *p说明了p是指向字符串的常量指针。
14. 可以用delete释放不是用new运算符分配的内存。
15. For循环是只有可以确定的循环次数时才可使用,否则不能用for循环。
解释:
1. 友元函数说明在类体内,它是一种成员函数。 (×)
解释:友元函数不是类的成员函数,它只是一个外部函数,但它被授予访问类私有和保护成员的权限。
2. 构造函数的名字必须与类名相同,其返回类型缺省为void类型。 (×)
解释:构造函数的名字必须与类名相同,但它没有返回类型(包括void)。
3. 运算符重载以后,其优先级和结合性都不能改变。 (√)
解释:运算符重载不能改变运算符的优先级和结合性,只能改变运算符的功能。
4. 在类Time中的析构函数可以声明为:void ~Time(int) 。 (×)
解释:析构函数不能有参数,也不能有返回类型。正确的析构函数声明为:~Time();
5. 纯虚函数是在基类中说明的虚函数,它在该基类中没有定义具体的操作内容。 (√)
解释:纯虚函数是一个在基类中声明但没有实现的虚函数,通常定义为virtual void function() = 0;
。
6. 在C++中,函数名实际上是一个指针,它指向函数的入口。 (√)
解释:在C++中,函数名可以被认为是指向函数入口点的指针,可以赋值给函数指针。
7. 常对象只能调用它的常成员函数, 而不能调用普通的成员函数。 (√)
解释:常对象只能调用常成员函数,因为常成员函数不会修改对象的状态,而普通成员函数可能会修改对象的状态。
8. 类静态成员数据为该类所有对象共享,在该类对象被撤销时,静态成员并不撤销。 (√)
解释:静态成员变量在所有对象间共享,并且其生命周期与类本身相同,不依赖于对象的存在。
9. 在声明一个类时,必须同时声明类的数据成员和成员函数。 (×)
解释:在声明一个类时,可以只声明数据成员或只声明成员函数,不需要同时声明两者。
10. 析构函数的作用是当对象不用时,删除对象。 (×)
解释:析构函数的作用是当对象被销毁时,执行清理工作。对象的销毁由程序控制,而不是析构函数直接删除对象。
11. 已知:int a=5,b=10; 表达式++a+b++有二义性。 (×)
解释:表达式 ++a + b++
没有二义性。它遵循明确的求值顺序:++a
先进行前置增量,b++
后进行后置增量。
12. 在传值调用中,要求实参和形参的类型完全一致并且个数相等。 (×)
解释:在传值调用中,实参的类型必须能够隐式转换为形参类型。它们不一定完全一致,但必须可转换。
13. const char *p说明了p是指向字符串的常量指针。 (×)
解释:const char *p
表示 p
是一个指向常量字符的指针,即通过 p
不能修改指针所指向的字符内容。
14. 可以用delete释放不是用new运算符分配的内存。 (×)
解释:不能用 delete
释放不是用
new
运算符分配的内存,这会导致未定义行为。内存释放必须与分配方式匹配。
15. For循环是只有可以确定的循环次数时才可使用,否则不能用for循环。 (×)
解释:虽然 for
循环通常用于已知次数的循环,但也可以用于未知次数的循环,只要循环条件和更新表达式合适。
四、下列小程序各1个错误,指出错误行数,并进行改正(每小题4分,共8分)
1. 类模板的对象定义
1 | ① template <class T> |
2. 包括静态数据的类定义
1 | ① class myClass { |
好的,以下是解释:
1. 类模板的对象定义
1 | ① template <class T> |
错误行数⑨
错误原因:模板类实例化时,使用模板参数的类型必须指定正确的类型名,而不是在模板参数的位置使用具体的类型。
改正:将 Tany (int)
改为
Tany<int>
改正后的代码:
1 | ⑧ Tany<int> obj(10, 100); |
2. 包括静态数据的类定义
1 | ① class myClass { |
错误行数⑦
错误原因:静态数据成员只能在类外定义和初始化,不能在类内直接初始化。
改正:将静态数据成员的初始化移到类定义外。
改正后的代码:
1 | ① class myClass { |
总结:
- 类模板的对象定义中,模板实例化需要用尖括号括住实际类型。
- 静态成员变量在类定义中声明,但在类外初始化。
五、程序填空题:下列程序中缺少若干条语句,每条下划线只填一条语句(每条语句2分,共14分)
1. 类 fraction
定义
1 | class fraction { |
2. 函数模板,用于计算两个向量的和
1 |
|
3. 链表结点的结构及逆置函数
reverse
1 | struct node { |
好的,以下是解释:
1. 类 fraction
定义
1 | class fraction { |
填空解释:
- (1)
" / " << fr.num
- 解释:
os << fr.den << " / " << fr.num
将分子和分母以分数形式输出,例如2/3
。
- 解释:
- (2)
os
- 解释:返回输出流对象
os
以支持链式操作。
- 解释:返回输出流对象
改正后的代码:
1 | ostream& operator<<(ostream& os, fraction& fr) { |
2. 函数模板,用于计算两个向量的和
1 |
|
填空解释:
- (3)
new T[n]
- 解释:
T* c = new T[n];
动态分配一个大小为n
的数组用于存储向量的和。
- 解释:
- (4)
a[i] + b[i]
- 解释:
c[i] = a[i] + b[i];
计算对应元素的和并存储在数组c
中。
- 解释:
改正后的代码:
1 | template<class T> |
3. 链表结点的结构及逆置函数
reverse
1 | struct node { |
填空解释:
- (5)
|| head->next == NULL
- 解释:
if(head == NULL || head->next == NULL)
检查链表是否为空或只有一个节点,如果是则无需逆置,直接返回头结点。
- 解释:
- (6)
head = p
- 解释:将当前节点
p
赋给head
,使head
指向当前节点,从而将节点插入到新链表的开头。
- 解释:将当前节点
- (7)
temp2->next = temp1
- 解释:将当前节点
temp2
的next
指针指向temp1
,即将当前节点链接到新链表的开头。
- 解释:将当前节点
改正后的代码:
1 | struct node* reverse(struct node* head) { |
六、简答题(每题4分,共12分)
1、简述结构化的程序设计、面向对象的程序设计的基本思想。
2、什么是this指针,其作用是什么?
3、若程序员没有定义拷贝构造函数,则编译器自动生成一个缺省的拷贝构造函数,它可能会产生什么问题?**
1. 简述结构化的程序设计、面向对象的程序设计的基本思想
结构化程序设计的基本思想:
- 分离数据和操作:在结构化程序设计中,数据和操作是分离的。数据通常由全局变量或局部变量表示,而操作则由函数实现。
- 模块化:程序是由一个个独立的函数组成的,这些函数通过参数传递数据和返回值来进行通信。
- 顺序、选择、循环:使用基本的控制结构(顺序、选择、循环)来组织程序逻辑。
- 降低复杂度:通过将程序划分为小的、可管理的模块(函数),使得程序更加清晰和易于维护。
面向对象程序设计的基本思想:
- 封装:将数据和操作封装在一个类中,数据成为类的成员变量,操作成为类的成员函数。通过这种方式,数据和操作紧密结合在一起。
- 对象:程序由一个个对象组成,每个对象是一个类的实例。对象通过接口进行通信和协作。
- 继承:允许一个类从另一个类继承数据和行为,从而实现代码复用和扩展。
- 多态:通过接口和继承关系,使得不同的对象可以通过相同的接口进行操作,实现灵活和可扩展的设计。
- 代码复用:由于类可以继承和组合,面向对象的程序设计能够较好地支持代码的复用。
2. 什么是 this
指针,其作用是什么?
this
指针:
- 定义:在每一个成员函数中都包含一个特殊的指针,这个指针的名字是固定的,称为
this
指针。它是指向当前对象的指针。 - 指向当前对象:
this
指针指向调用该成员函数的对象,即当前被调用的成员函数所在的对象的起始地址。 - 作用:
this
指针主要用于:- 访问当前对象的成员变量和成员函数。
- 在重载运算符时,返回对象本身以支持链式操作。
- 在需要返回对象本身的成员函数中返回
*this
。
- 多对象共享函数:通过
this
指针,同一个类创建的多个对象共用同一份成员函数的拷贝,也知道是取哪个对象的成员数据。
3. 若程序员没有定义拷贝构造函数,则编译器自动生成一个缺省的拷贝构造函数,它可能会产生什么问题?
缺省拷贝构造函数可能产生的问题:
- 浅拷贝:缺省的拷贝构造函数只进行浅拷贝,即将对象的每个数据成员简单地复制给新对象。如果对象包含指针数据成员,那么指针成员所指向的内存地址也会被复制,而不是指针所指向的内容。
- 内存泄漏:由于浅拷贝只是复制指针而不是实际内容,当一个对象被销毁时,它所指向的内存单元会被释放。如果同一个内存单元被多个对象共享,销毁其中一个对象后,其他对象仍然指向已经被释放的内存单元,这会导致悬挂指针问题。
- 双重释放:由于多个对象共享同一个内存地址,当这些对象被销毁时,会尝试释放同一个内存单元多次,这将导致程序运行错误,甚至崩溃。
七、编程题(9分)
定义一个复数类Complex,它的私有数据成员(类型都是float)有real(实数), imag(虚数),公有成员函数有:GetReal(),它返回复数的实数部分;GetImag(),它返回复数的虚数部分;Complex operator +( Complex &),返回两个复数的加。该复数的构造函数原型为:Complex(float r=1.0, float i=1.0)。
要求: 编写类Complex及成员函数,并编写一个主程序,主程序中定义了2个复数(其中有一个复数的参数为默认参数,另一个参数可以是任意有效值),然后,计算2个复数的加,并输出结果。
好的,以下是完整的 Complex
类定义及其成员函数的实现,同时包含主程序部分,用于定义两个复数对象并计算它们的和:
1 |
|
代码说明
- 类定义:
Complex
类有两个私有成员变量:real
和imag
,分别表示复数的实数部分和虚数部分。- 构造函数
Complex(float r = 1.0, float i = 1.0)
使用默认参数初始化复数对象。 - 公有成员函数
GetReal()
和GetImag()
返回复数的实数部分和虚数部分。 - 重载的加法运算符
operator+
实现两个复数相加并返回结果。 - 成员函数
Display()
用于输出复数。
- 主程序:
- 定义了两个复数对象
c1
和c2
,其中c1
使用默认参数,c2
使用自定义参数。 - 使用重载的加法运算符计算两个复数的和,并将结果存储在
c3
中。 - 使用
Display()
函数输出复数和结果。
- 定义了两个复数对象
输出结果
运行该程序时,输出如下:
1 | 第一个复数: (1 + 1i) |
这个程序展示了如何定义和使用一个包含默认参数的复数类,重载运算符,以及在主程序中进行对象的创建和操作。