实验六 构造函数+拷贝构造
A. 身体评估(类与对象)
题目描述
评估成年人身体健康有多个指标,包括BMI、体脂率BFR等
设计一个身体健康类,包含私有成员:姓名、身高(米)、体重(公斤),腰围(厘米),实现两个公有方法如下:
BMI方法,返回BMI数值(整数),计算公式BMI= 体重 / 身高的平方
体脂率方法,返回体脂率数值(浮点数),计算过程如下:
1)参数a=腰围(cm)×0.74
2)参数b=体重(kg)×0.082+34.89
3)体脂肪重量(kg)=a-b
4)体脂率 = 体脂肪重量÷体重
其它方法根据需要自行定义
输入
第一行输入t表示有t个测试实例
第二行起,每行输入四个参数:姓名、身高、体重,腰围
依次输入t行
输出
输出t行,每行输入一个实例的BMI和体脂率,小数数值精确到小数点后2位,用空格隔开
输入样例
2
David 1.85 78.5 85.2
Sara 1.55 67.6 77.3
输出样例
David's BMI: 23--BFR: 0.28
Sara's BMI: 28--BFR: 0.25
参考代码
#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;
class Body
{
string name;
float lenth;
float weight;
float rou;
public:
Body(string nam,float len,float wei,float roug)
{
name=nam;
lenth=len;
weight=wei;
rou=roug;
}
int BMI()
{
float bmi=weight/(lenth*lenth);
int a=round(bmi);//四舍五入
return (a);
}
float BFR()
{
float a=rou*0.74;
float bfr=(a-(weight*0.082+34.89))/weight;
return bfr;
}
void print()
{
cout<<name<<"'s BMI: ";
}
};
int main()
{
int t;
cin>>t;
while(t--)
{
string name;
float lenth,weight,rou;
cin>>name>>lenth>>weight>>rou;
Body body(name,lenth,weight,rou);
int bm=body.BMI();
float bf=body.BFR();
body.print();
cout<<bm<<"--BFR: "<<fixed<<setprecision(2)<<bf<<endl;
}
}
B. 生日打折(复合类构造)
题目描述
定义一个日期类Date,包含数据成员year\month\day,还包含构造函数及其他函数(根据需要自己添加)
定义一个会员类VIP,包含数据成员id和birth,其中id是整数表示会员编号;birth是Date类型表示生日。
类VIP包含构造函数和其他函数(根据需要自己添加),还包含一个折扣函数Discount。函数Discount返回结果为浮点数表示折扣,函数包含1个参数为日期类型,函数功能是判断参数日期是否会员生日,是则折扣为0.5,不是则折扣为0.95
编写程序实现上述类功能并实现输入输出的要求
输入
第一行输入年、月、日,表示今天日期
第二行输入t表示有t个会员
第三行输入第1个会员的ID、生日的年、月、日
第四行输入第1个会员的消费金额
依次类推输入下一个会员的两行数据…
输出
根据会员的消费金额,调用Discount函数判断今天是否会员生日并得到折扣,然后计算会员打完折的消费金额
每一行先输出会员编号,再输出会员打完折的消费金额,消费金额只需要输出整数部分
提示把浮点数转整数:
double x = 123.456
cout<<int(x)<<endl;
输入样例
2017 4 20
2
1111 2000 4 20
136
2222 2000 3 30
125
输出样例
1111's consumption is 68
2222's consumption is 118
参考代码
#include<iostream>
using namespace std;
class Date
{
int year;
int month;
int day;
public:
Date(){}
Date(int y,int m,int d)
{
year=y;
month=m;
day=d;
}
int get_month(){return month;}
int get_day(){return day;}
};
class VIP
{
string id;
Date birth;
public:
VIP(string i,Date &bir0)
{
id=i;
birth=bir0;
}
float Discount(Date a)
{
float dis;
if((a.get_month()==birth.get_month())&&(a.get_day()==birth.get_day()))
dis=0.5;
else dis=0.95;
return dis;
}
void print()
{
cout<<id<<"'s consumption is ";
}
};
int main()
{
int y1,m1,d1;//今天
int y2,m2,d2,t;
string id;
cin>>y1>>m1>>d1>>t;
Date today(y1,m1,d1);
double cost;
while(t--)
{
cin>>id>>y2>>m2>>d2;
Date bir(y2,m2,d2);
VIP n(id,bir);
float disc;
cin>>cost;
disc=n.Discount(today);
cost=cost*disc;
n.print();
cout<<int(cost)<<endl;
}
}
C. 电话号码升位(拷贝构造函数)
题目描述
定义一个电话号码类CTelNumber,包含1个字符指针数据成员,以及构造、析构、打印及拷贝构造函数。
字符指针是用于动态创建一个字符数组,然后保存外来输入的电话号码
构造函数的功能是为对象设置键盘输入的7位电话号码,
拷贝构造函数的功能是用原来7位号码的对象升位为8位号码对象,也就是说拷贝构造的对象是源对象的升级.电话升位的规则是原2、3、4开头的电话号码前面加8,原5、6、7、8开头的前面加2。
注意:合法的电话号码:1、长度为7位;2、电话号码的字符全部是数字字符;3、第一个字符只能是以下字符:2、3、4、5、6、7、8。与上述情况不符的输入均为非法
输入
测试数据的组数 t
第一个7位号码
第二个7位号码
…
输出
第一个号码升位后的号码
第二个号码升位后的号码
…
如果号码升级不成功,则输出报错信息,具体看示例
输入样例
3
6545889
3335656
565655
输出样例
26545889
83335656
Illegal phone number
参考代码
#include<iostream>
#include<cstring>
using namespace std;
class CTelNumber
{
char *num;
public:
CTelNumber()
{
num=new char[8];
}
CTelNumber(char *q)
{
num=new char[8];
strcpy(num,q);
}
CTelNumber(CTelNumber &a)
{
int i;
num=new char[9];//升级
//已经知道他合法
if(a.num[0]=='2'||a.num[0]=='3'||a.num[0]=='4') num[0]='8';
else num[0]='2';
for(i=0;i<7;i++)
{
num[i+1]=a.num[i];
}
}
~CTelNumber()
{
delete num;
}
void print()
{
int i=0;
for(i=0;i<8;i++)
{
cout<<num[i];
}
cout<<endl;
}
};
int main()
{
int t;
cin>>t;
while(t--)
{
int flag=1;
char *q=new char[8];
cin>>q;
for(int i=0;i<7;i++)
{
if(q[0]<'2'||q[0]>'8')
{
flag=0;
break;
}
if(q[i]<'0'||q[i]>'9')
{
flag=0;
break;
}
}
if(flag==0) cout<<"Illegal phone number"<<endl;
else
{
CTelNumber num1(q);//调用构造储存q
CTelNumber num2(num1);//调用拷贝构造升级q
num2.print();
}
}
}
D. 彩票复制(拷贝构造)
题目描述
假设每组彩票包含6个号码,设计一个彩票类lottery,数据成员包括第一组号码、其他组数、其他组号码,描述如下
1、第一组号码group1,整数数组,长度为6
2、其他组数num,表示以第一组号码为样本,创建num组其他号码
3、其他组号码groupn,整数指针(int **),,该数据将动态创建二维整数数组,共9行,每行包含6个号码。
彩票类的成员函数包括:构造函数、拷贝构造函数、打印,描述如下:
1、打印函数,输出彩票的所有组的号码
2、构造函数,两个参数,第一个参数为整数数组,对应第一组号码,第二个参数为整数,表示其他组数(不超过9)。注意在构造函数中,其他组号码groupn不动态分配空间,仍然为指针
3、拷贝构造函数,其他组号码groupn动态创建二维数组,根据其他组数创建其他组的号码,创建规则为:
a)第i组的第j个号码等于上一组第j-1个号码加1,首个号码等于上一组最后一个号码加1
例如第一组号码group1的号码是1、3、5、7、9、11,且其他组数为2
则groupn的第0组号码是12、2、4、6、8、10,第1组号码是11、13、3、5、7、9,以此类推
输入
第一行输入t表示有t个样例,每个样例对应一行数据
接着一行输入7个参数,前6个参数表示首张彩票的第一组6个号码,第7个参数表示其他组数,这时使用使用构造函数
然后采用拷贝构造方法生成第二张彩票,其中复制了首张彩票的第一组号码和其他组数,并且生成其他组号码
依此类推
输出
调用Print方法,输出每个样例中第二张彩票的所有组的号码
输入样例
2
1 3 5 7 9 11 2
22 44 66 88 100 122 3
输出样例
1 3 5 7 9 11
12 2 4 6 8 10
11 13 3 5 7 9
22 44 66 88 100 122
123 23 45 67 89 101
102 124 24 46 68 90
91 103 125 25 47 69
参考代码
#include<iostream>
using namespace std;
class lottery{
int group1[6];
int num;
int **grounpn;
public:
lottery(){grounpn=NULL;}
lottery(int a[6],int n)
{
for(int i=0;i<6;i++)
{
group1[i]=a[i];
}
num=n;
grounpn=NULL;
}
lottery(lottery &l1)
{
num=l1.num;
for(int i=0;i<6;i++)
{
group1[i]=l1.group1[i];
}
grounpn=new int*[num];
for(int i=0;i<num;i++)
{
grounpn[i]=new int[6];
}
for(int i=0;i<6;i++)
{
if(i==0) grounpn[0][i]=group1[5]+1;
else grounpn[0][i]=l1.group1[i-1]+1;
}
for(int i=1;i<num;i++)
{
grounpn[i][0]=grounpn[i-1][5]+1;
for(int j=1;j<6;j++)
{
grounpn[i][j]=grounpn[i-1][j-1]+1;
}
}
}
void print()
{
for(int i=0;i<6;i++)
{
if(i<5) cout<<group1[i]<<' ';
else cout<<group1[i]<<endl;
}
for(int i=0;i<num;i++)
{
for(int j=0;j<6;j++)
{
if(j<5) cout<<grounpn[i][j]<<' ';
else cout<<grounpn[i][j]<<endl;
}
}
}
~lottery()
{
if(grounpn!=NULL)
{
for(int i=0;i<num;i++)
delete []grounpn[i];
delete []grounpn;
}
}
};
int main()
{
int t;
cin>>t;
int nu[6],num;
while(t--)
{
for(int i=0;i<6;i++)
{
cin>>nu[i];
}
cin>>num;
lottery lo1(nu,num);
lottery lo2(lo1);
lo2.print();
}
}
E. 身份证设定(复合类+拷贝构造)
题目描述
定义一个身份证类PID,包含私有属性:身份证类型、身份证号码、出生日期;另外包含方法:构造、拷贝构造打印等。
身份证类型表示一代身份证或者二代身份证,分别用1和2表示
身份证号码是一个字符串,长度为15或者18
出生日期是一个类,包含私有属性年、月、日,以及构造函数等(根据需要添加其他方法)
构造函数要注意是复合类,要考虑复合类成员的构造
打印函数把身份证的所有属性都输出,输出格式看示例
拷贝构造作用:如果身份证号码是15位的就升级为18位,包括把身份证类型改为2,然后把号码扩展,规则如下:
-
原15位身份证的第7位到12位表示出生年月日,每个两位;把年份的2位扩展为四位。
-
把扩展后的17个数字求和,取总和的末尾数字,如果末尾数字是0,则将0改为X,然后把这个数字作为第18位
3.如果身份证号码已经是18位,就无需升级
例如身份证123456910203000,表示91年2月3日出生,然后根据类属性出生日期知道是1991年,不是2091年。因此扩展为12345619910203000
接着把17个数字相加得到46,取末尾6,最终扩展为123456199102030006
输入
第一行输入t表示t个示例
第二行输入一个身份证的5个属性,顺序为:类型、号码、出生年、月、日
依次输入t行
输出
采用拷贝构造函数的方法对身份证号码升级,然后输出
输入样例
3
1 123456910203000 1991 2 3
2 654321200001018889 2000 1 1
1 234567001217000 2000 12 17
输出样例
type=2 birth=1991.02.03
ID=123456199102030006
type=2 birth=2000.01.01
ID=654321200001018889
type=2 birth=2000.12.17
ID=23456720001217000X
参考代码
#include <iostream>
#include<string.h>
using namespace std;
class birthday
{
int year,month,day;
public :
birthday(int y=0,int m=0,int d=0)
{
year=y;month=m;day=d;
}
void set(int yy,int mm,int dd)
{
year=yy;month=mm;day=dd;
}
int getyear()
{
return year;
}
int getmonth()
{
return month;
}
int getday()
{
return day;
}
void print()
{
printf("%d.%02d.%02d",year,month,day);
}
};
class PID
{
int lei;
char *num;
birthday th;
public:
PID(int l,char *ch,int y,int m,int d)
{
lei=l;
num=new char [strlen(ch)+1];
strcpy(num,ch);
th.set(y,m,d);
}
PID(PID &r)
{
num=new char [19];
lei=2;
th.set(r.th.getyear(),r.th.getmonth(),r.th.getday());
if(strlen(r.num)==18) strcpy(num,r.num);
else {
int s=0;
for(int i=0;i<6;i++)
{
num[i]=r.num[i];
s+=num[i]-'0';
}
for(int i=8;i<=16;i++)
{
num[i]=r.num[i-2];
s+=num[i]-'0';
}
int k=th.getyear();
num[6]=k/1000+'0';
num[7]=k/100%10+'0';
s+=num[6]-'0';
s+=num[7]-'0';
if(s%10==0) num[17]='X';
else num[17]=s%10+'0';
}
num[18]='\0';
}
void out()
{
cout<<"type=2"<<" birth=";
th.print();
cout<<endl;
cout<<"ID="<<num<<endl;
}
~PID()
{
delete[] num;
}
};
int main()
{
int t,a,b,c,d;
char k[30];
cin>>t;
while(t--)
{
cin>>a>>k>>b>>c>>d;
PID p(a,k,b,c,d);
PID q(p);
q.out();
}
return 0;
}