一、判断题
1、当用一个对象去初始化同类的另一个对象时,要调用拷贝构造函数。
T F
解析:T。在使用一个对象来初始化同类的另一个对象时,我们会选择调用拷贝构造函数。拷贝构造函数是一种特殊的构造函数,用于创建一个新对象,该对象与传递给它的现有对象具有相同的属性和状态。
2、对象间赋值将调用拷贝构造函数。
T F
解析:对象间的赋值通常会调用赋值运算符“=”,而不是拷贝构造函数。
二、选择题
1、下列各类函数中,不是类的成员函数的是
A.构造函数 B.析构函数 C.友元函数 D.拷贝构造函数
解析:C。友元函数不属于类的成员函数。
2、设类AA已定义,假设以下语句全部合法,哪些语句会触发调用拷贝构造函数( )。
AA a, b; //1
AA c(10, 20); //2
AA d(c); //3
AA e = d; //4
A.2 B.3 C.4 D.3 和 4
解析:D。拷贝构造函数主要在以下情况下被调用:1、初始化:当使用一个已有的对象来初始化一个新对象时,会调用拷贝构造函数。2、传递函数参数:当将对象作为函数参数传递给一个函数时,拷贝构造函数会被调用。3、从函数返回对象:当函数返回一个对象时,拷贝构造函数也可能被调用。而此处中3为将对象c作为函数参数传递给另一个对象,而4为使用一个已有的对象对于另一个对象进行初始化,故为调用了拷贝构造函数。
3、假设MyClass是一个类,则该类的拷贝初始化构造函数的声明语句为( )
A.MyClass&(MyClass x);
B.MyClass(MyClass x);
C.MyClass(MyClass &x);
D.MyClass(MyClass *x);
解析:C。拷贝构造函数的具体申明书写格式就是MyClass(MyClass &x);
4、下列关于异常类的说法中,错误的是。
A.异常类由标准库提供,不可以自定义
B.C++的异常处理机制具有为抛出异常前构造的所有局部对象自动调用析构函数的能力
C.若catch块采用异常类对象接收异常信息,则在抛出异常时将通过拷贝构造函数进行对象复制,异常处理完后才将两个异常对象进行析构,释放资源
D.异常类对象抛出后,catch块会用类对象引用接收它以便执行相应的处理动作
解析:A。异常类可以在标准库中调用,也可以自己加以申明与定义。
5、下列哪一个说法是错误的?
A.当用一个对象去初始化同类的另一个对象时,要调用拷贝构造函数
B.如果某函数有一个参数是类A的对象,那么该函数被调用时,类A的拷贝构造函数将被调用
C.如果函数的返回值是类A的对象时,则函数返回时,类A的拷贝构造函数将被调用
D.拷贝构造函数必须自己编写
解析:D。在默认情况下,编译器会生成一个简单的拷贝构造函数,但是如果需要特定的行为,也可以自己编写这个拷贝构造函数。
6、假设A是一个类的名字,下面哪段程序不会用到A的拷贝构造函数?
A.A a1,a2; a1=a2;
B.void func( A a) { cout<<"good"<< endl; }
C.A func() { A tmp; return tmp;}
D.A a1; A a2(a1);
解析:A。因为这里发生的是赋值操作,而不是对象的初始化或参数传递。赋值操作使用已经创建的对象 a1
来接收 a2
的值,而不是通过拷贝构造函数创建一个新对象。
7、如果某函数的返回值是个对象 ,则该函数被调用时,返回的对象?
A.是通过拷贝构造函数初始化的
B.是通过无参数的构造函数初始化的
C.用哪个构造函数初始化,取决于函数中return 语句是怎么写的
D.不需要初始化
解析:A。当函数返回一个对象时,其是通过拷贝构造函数将其进行初始化的。
三、函数题
1、实现数组类(C++ 拷贝构造函数、拷贝函数)
裁判测试程序样例中展示的是一段实现“数组类”的代码,其中缺失了部分代码,请补充完整,以保证测试程序正常运行。
函数接口定义:
提示:要想程序正确运行,至少需要补充以下函数(可能还需要补充其他函数):
1. 带参构造函数
2. 拷贝构造函数
3. 拷贝函数(赋值运算符重载)
裁判测试程序样例:
#include <iostream>
using namespace std;
class ArrayIndexOutOfBoundsException{ // 异常类
public:
int index;
ArrayIndexOutOfBoundsException(int k){
index = k;
}
};
class Array{
private:
int *data;
int size;
static const int dSize = 10; // 数组默认大小
public:
Array( ){ // 无参构造
size = dSize;
data = new int[size]( );
}
/** 你提交的代码将被嵌在这里(替换本行内容) **/
int& operator [] (int k){ // 运算符 [ ] 重载,以方便数组的使用
if(k<0 || k>=size) throw ArrayIndexOutOfBoundsException(k);
return data[k];
}
friend ostream& operator << (ostream& o, const Array& a); // 运算符 << 重载,以方便输出
};
ostream& operator << (ostream& o, const Array& a){
o << '[' ;
for(int i=0; i<a.size-1; i++)
o << a.data[i] << ',' ;
o << a.data[a.size-1] << ']';
return o;
}
// 注意:实际测试程序中,在此处之前的代码与样例中相同
// 注意:实际测试程序中,在此处之后的代码(即main函数)可能与样例中不同
int main(){
int n, k;
cin >> n >> k;
Array a(n); // 构造数组,大小为 n
for(int i=0; i<n; i++) a[i] = i;
Array b = a; // 拷贝构造数组
b[n/2] = k;
cout << a << endl;
cout << b << endl;
Array c; // 构造数组,默认大小
c = a; // 拷贝数组
c[n/2] = k;
cout << a << endl;
cout << c << endl;
a = a;
a[n/2] = 2223;
cout << a << endl;
return 0;
}
输入样例:
15 666
输出样例:
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
[0,1,2,3,4,5,6,666,8,9,10,11,12,13,14]
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
[0,1,2,3,4,5,6,666,8,9,10,11,12,13,14]
[0,1,2,3,4,5,6,2223,8,9,10,11,12,13,14]
代码解答:
Array(int n)
{
size = n;
data = new int[size]();
}
Array(const Array& a)
{
size = a.size;
data = new int[size]();
for (int i = 0; i < size; i++)
{
data[i] = a.data[i];
}
}
Array& operator=(const Array& a)//重载“=”,便于类对象的data数组赋值
{
if (a.size != size)
{
delete[]data;
size = a.size;
data = new int[size];
}
for (int i = 0; i < size; i++)
{
data[i] = a.data[i];
}
return *this; //this指针返回本函数本身的Array
}
~Array()
{
delete[]data;//写析构函数是个好习惯,节约内存
}