实验18+构造函数和析构函数
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验18 构造函数和析构函数
一、实验目的和要求
1.理解构造函数和析构函数的作用。
2.能熟练编写构造函数和析构函数,进一步锻炼针对类的编程能力。
二、实验准备
☞知识点
1.构造函数和析构函数的定义、使用方法及异同
(1)构造函数是用来____________________的一种特殊的成员函数,在________被创建时自动执行,当对象撤销时自动执行的成员函数称之为__________。
(2)构造函数_____返回值,_____指定为void类型,_____重载,_____带参数。
析构函数_____返回值,_____指定为void类型,_____重载,_____带参数。
2.类型转换构造函数
(1)类型转换构造函数分为两种:__________________和__________________。
(2)假设类A存在只带一个整型参数的构造函数,则定义”A a=10;”等价于____________。
3.拷贝构造函数
(1)拷贝构造函数分为两种:__________________和__________________。
(2)拷贝构造函数的参数通常是____________________________________。
4
表18-1 构造函数、析构函数调用时间一览表
5.动态分配和释放对象的存储空间
(1)new和delete总成对出现,动态分配存储空间时会调用_______函数,收回存储空间时会调用_______函数。
(2)new出现在类体(一般是构造函数)内,则delete也应出现在类体(一般是析构函数)内。
(3)new出现在类体外,则delete也应出现在类体外。
(4)撤销对象时,系统只自动收回非动态分配的存储空间,而不自动收回动态申请的空间。
6.对象成员的初始化及应用
(1)___________________________________________,称之为对象成员。
(2)类中对象数据成员的初始化工作必须在_________________完成。
(3)对象成员初始化的顺序取决于__________________________________。
(4)创建具有对象成员的类的对象时,构造函数的调用先后顺序:__________________
_____________________________________________________________________。
☞课前练习题
1.在定义一个类时,缺省的构造函数是唯一的。
当自定义的构造函数的每一个参数均有缺
省值或时,这种构造函数是确省的构造函数。
2.下面哪一个不是构造函数的特征_。
A.构造函数的函数名与类名相同B.构造函数不能重载
C.构造函数可以设置缺省参数D.构造函数没有类型
3.类的析构函数的作用是_。
A.一般成员函数B.类的初始化C.对象的初始化D.删除对象
4.对于一个C++的类, _。
A.只能有一个构造函数和一个析构函数
B.可有一个构造函数和多个析构函数
C.可有多个构造函数和一个析构函数
D.可有多个构造函数和多个析构函数
5.假定AB为一个类,则该类的拷贝构造函数的声明语句为_。
A.AB&(AB x); B.AB(AB x); C.AB(AB* x); D.AB(AB&); 6.若AB为某个类的类名,执行语句“AB a[5];“后,系统自动调用该类的构造函数的次数为________。
分析
1.有以下程序:
#include<iostream.h>
class Test
{
private:
int x,y;
public:
Test(){ x=0;y=0; }
Test(int x,int y)
{
this->x=x;
this->y=y;
}
void print(){ cout<<"x="<<x<<",y="<<y<<endl; }
};
void main()
{
Test t1; //行A
Test t2(50,100); //行B
Test *p[]={&t1,&t2};
t2=Test(100,200); //行C
for(int i=0;i<=1;i++)
p[i]->print();
}
请回答问题:
①行A定义了一个类Test的对象,它将调用哪个构造函数?____________________。
②行A能否写成Test t1(); ?_________。
如果不可以,Test t1();代表什么含义?___________________________________________。
③行B定义了另一个类Test的对象,它将调用哪个构造函数?____________________。
④解释第二个构造函数的函数体中用到this指针的原因:______________________________ _________________________________________。
⑤行C中的Test可否去掉?________。
解释行B的含义:_____________________________。
2.有以下程序:
#include <iostream.h>
#include <string.h>
class String
{
char *s;
public:
String(char *p=0)
{
if(p)
{
s=new char[strlen(p)+1]; //行A
strcpy(s,p);
}
else s=0;
}
String(String &p) //行B
{
if(p.s)
{
s=new char[strlen(p.s)+1];
strcpy(s,p.s);
}
else s=0;
}
~String()
{ if(s) delete []s;}
void Show()
{ cout<<"s="<<s<<'\n';}
};
void main(void)
{
String s1("张三");
String s2(s1); //行C
s1.Show();
s2.Show();
}
请回答问题:
①行A中动态申请的数组大小为何还要加1?_____________________________。
②String类中是否还存在默认的构造函数String();?______________________________。
③行B开始的构造函数称之为_________构造函数。
解释其功能。
④执行行C时会调用哪个构造函数?_____________________________。
如果将行B开始的构造函数删掉,执行行C时会有什么问题?
⑤如果在main函数加一条语句:s2=s1; ,运行本程序又会出现什么问题?
⑥上机验证输出结果。
三、实验内容
1.建立一个类PrimeNUM,求指定数据范围内的所有素数(质数)。
具体要求如下:
(1)私有数据成员
●int data[25]:依次存放在指定范围内求出的所有素数。
●int low,high:存放指定的数据范围的下限和上限。
●int num:存放low与high之间的素数个数。
(2)公有成员函数
●PrimeNUM(int _low,int _high):构造函数,用参数_low和_high初始化low和high,同时初始化num。
●int isprime(int x):判断x是否为素数。
若是素数,返回1;否则,返回0。
●void process():求指定范围内的所有素数,把它们依次存放在数组data中,并将求出的素数个数赋给num。
●void print():输出求出的素数个数及所有素数,每行输出5个素数。
(3)在主函数中对该类进行测试。
定义一个PrimeNUM类的对象test,指定查找范围为100~150,即求100至150之间的所有素数。
通过test调用成员函数完成求素数及输出素数的工作。
本题正确的输出结果应为:
num=10
101 103 107 109 113
127 131 137 139 149
2.建立一个类SUM,求二维数组外围各元素的和,并且输出数组各元素及所求之和。
具体要求如下:
(1)私有数据成员
●int a[4][4]:二维数组,存放要处理的数据。
●int s:存放数组a外围各元素的和。
(2)公有成员函数
●SUM(int b[4][4]):构造函数,用数组b初始化数组a。
●void process():求二维数组外围各元素的和s。
●void print():按行列方式输出数组a的各元素值,并输出外围各元素的和。
(3)在主函数中完成对该类的测试。
使用如下测试数据(外围元素是指阴影部分的元素):
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
3.建立一个矩阵类Matrix ,存储一个4*4的矩阵并能在矩阵中查找某数。
要求如下:
(1)私有数据成员
● int p[4][4]:存储一个4*4的矩阵的值。
● int n :矩阵的行数。
● int x :存储根据查找要求在矩阵中要查找到的某数。
● int row ,col :存储该数所在的行、列值。
(2)公有成员函数
● 构造函数:初始化n 的值为4,x 、row 、col 为0。
● void input(int a[][4]):将一个矩阵赋给该对象中的数组。
● void find( ):在该对象存储的矩阵中查找值最小的数,保存该数及该数所在的行、列值到x 、row 、col 中。
● void print( ):按行输出矩阵的值。
(3)在主函数中测试该类,使用以下测试数据,输出矩阵的值,查找值最小的数并输出x 、row 、col 的值。
⎥⎥⎥⎥⎦
⎤⎢⎢⎢⎢⎣⎡12111094321161514138765
4.设定义一个类:
class ListArray
{
private:
int size; //整型数组的大小,表示可放元素的个数
int elem; //整型数组当前的元素个数,初始应为0,当elem 等于size 时,数组满 int *p; //指向整型数组,动态分配内存空间
public:
ListArray(int s=100); //用s 初始化整型数组的大小
void put(int n); //将n 加入整型数组,elem 自增1
void print(); //输出整型数组所有元素
~ListArray();
};
请完成该类成员函数的定义和测试程序的设计。
【提示】编写void put(int n)函数时,注意考虑数组满的情况。
如果数组已满,则没有空间存储n ,此时需动态申请新的内存空间,其大小应比原数组大小大1,并将原数组元素备份到新数组,新数组的最后一个元素存放n ,当然不要忘记释放为原数组动态分配的内存空间。
四、课后练习题
1.下列说明有关构造函数的正确说法是
A .任一类必定有构造函数
B .可定义没有构造函数的类
C .构造函数不能重载
D .任一类必定有缺省的构造函数
2.一个类的析构函数。
A.是唯一的B.允许重载C.至多可有两个D.只能是缺省的
3.下列有关类的构造函数和析构函数的说法中,不正确的是
A.类的析构函数可以重载
B.类的构造函数可以重载
C.定义一个类时可以不显式的定义构造函数
D.定义一个类时可以不显式的定义析构函数
4.以下有关对象的叙述中,不正确的是。
A. 产生对象时必定要调用构造函数
B. 撤消对象时必定要调用析构函数
C. 对象被保护,其私有成员不能任意访问
D. 对象可以没有构造函数或析构函数5.设P是指向一个类动态对象的指针变量,则执行语句”delete P;”时,将自动调用该类的______________。
6.已定义类A,该类构造函数的参数都没有缺省值。
执行语句:”A a1,a2(1,2),a3[3][3],*p1=&a1,*p2[3]={&a2, &a2, &a2},(*p3)[3]=a3,*p4=new A[3];”后,系统自动调用该类的缺省(无参)构造函数的次数为________。
7.以下程序对反映学生情况的数组a进行排序,按其数组元素的成员id(学号)从小到大排序。
请完善填空。
[程序]
#include<isotream.h>
class Elem
{ //描述一名学生的成绩和学号
int score; //成绩
int id; //学号
public:
Elem(int s=0,int i=0)
{
score=s;
id=i;
}
int Key() //获取学号
{ return id; }
int GetScore( ) //获取成绩
{ return score; }
};
void Select(Elem a[],int n)
{
for(int i=0;i<n-1;i++)
{
int min=a[i].Key( );
int p=i,j;
Elem temp;
for(j=i+1;j<n;j++)
if(a[j].Key()<min)
{ min= ;
;
}
if(p!=i)
{ ; a[i]=a[p];a[p]=temp;}
}
}
void main(void)
{
int s[]={56,78,65,90,88,76,72,80};
int id[]={8,1,2,6,7,4,3,5};
Elem a[8];
for(int i=0;i<8;i++)
a[i]= ____;
Select(a,8);
for(int j=0;j<8;j++)
cout<<a[j].GetScore()<<'\t'<<a[j].Key( )<<'\n';
}
8.以下程序的输出结果为______________。
#include<iostream.h>
#include<math.h>
class Point
{
private:
float x,y;
public:
Point(float x1,float y1){ x=x1;y=y1; }
float getx(){ return x; }
float gety(){ return y; }
};
class Line
{
private:
Point p1,p2;
float length;
public:
Line(float x1,float y1,float x2,float y2):p1(x1,y1),p2(x2,y2){}
void calcLength()
{
length=sqrt(pow(p1.getx()-p2.getx(),2)+pow(p1.gety()-p2.gety(),2));
}
void dispLength(){ cout<<length<<endl; }
};
void main()
{
Line line(0,0,3,4);
line.calcLength();
line.dispLength();
}。