id:45 A.Equation(类与对象+构造)
题目描述
建立一个类Equation,表达方程ax2+bx+c=0。类中至少包含以下方法:
-
无参构造(abc默认值为1.0、1.0、0)与有参构造函数,用于初始化a、b、c的值;
-
set方法,用于修改a、b、c的值
-
getRoot方法,求出方程的根。
一元二次方程的求根公式如下:
一元二次方程的求解分三种情况,如下:
输入
输入测试数据的组数t
第一组a、b、c
第二组a、b、c
输出
输出方程的根,结果到小数点后2位
在C++中,输出指定精度的参考代码如下:
#include <iostream>
#include <iomanip> //必须包含这个头文件
using namespace std;void main( )
{double a =3.14;cout<<fixed<<setprecision(3)<<a<<endl; //输出小数点后3位
}
输入样例
3
2 4 2
2 2 2
2 8 2
输出样例
x1=x2=-1.00
x1=-0.50+0.87i x2=-0.50-0.87i
x1=-0.27 x2=-3.73
题解
- 首先分析类,
Equation();
,无参构造,用于初始化abc的值;void set(double m, double n, double p);
,用于将abc的值修改为参数的值;void getRoot();
求根的函数,在函数中,我们首先定义一个变量来记录b * b - 4 * a * c
的值,然后通过这个值的判断,分为三种情况进行讨论,注意,当这个变量小于零时,我们开平方时需要开这个变量的相反数,最后做一些细节处理输入输出即可 - 在主函数中,我们输入abc的值后,调用设置值的函数,将输入的值传递到类的变量中,然后进行x值的输出
代码实现
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;class Equation
{
private:double a, b, c;
public:Equation(); // 无参构造,初始化void set(double m, double n, double p); // 修改a, b, c的值void getRoot(); // 求根
};Equation::Equation()
{a = 1.0;b = 1.0;c = 0;
}void Equation::set(double m, double n, double p)
{a = m;b = n;c = p;
}void Equation::getRoot()
{double x1, x2, t, j1, k1, k2;t = b * b - 4 * a * c;if (t == 0){x1 = (-b + sqrt(t)) / (2 * a);cout << "x1=x2=" << fixed << setprecision(2) << x1 << endl;}else if (t > 0){x1 = (-b + sqrt(t)) / (2 * a);x2 = (-b - sqrt(t)) / (2 * a);cout << "x1=" << fixed << setprecision(2) << x1 << " x2=" << fixed << setprecision(2) << x2 << endl;}else // 共轭复数{j1 = -b / (2 * a);k1 = (sqrt(-t)) / (2 * a);k2 = (sqrt(-t)) / (2 * a);cout << "x1=" << fixed << setprecision(2) << j1 << "+" << fixed << setprecision(2) << k1;cout << "i x2=" << fixed << setprecision(2) << j1 << "-" << fixed << setprecision(2) << k2 << "i" << endl;}
}int main()
{int t, i;double aa, bb, cc;Equation y;cin >> t;for (i = 0; i < t; i++){cin >> aa >> bb >> cc;y.set(aa, bb, cc);y.getRoot();}return 0;
}
id:50 B.对象是怎样构造的(拷贝构造函数)
题目描述
某个类包含一个整型数据成员.程序运行时若输入0表示用缺省方式定义一个类对象;输入1及一个整数表示用带一个参数的构造函数构造一个类对象;输入2及一个整数表示构造2个类对象,一个用输入的参数构造,另一个用前一个对象构造。试完成该类的定义和实现。
输入
测试数据的组数 t
第一组数
第二组数
…
输出
第一个对象构造输出
第二个对象构造输出
…
输入样例
3
0
1 10
2 20
输出样例
Constructed by default, value = 0
Constructed using one argument constructor, value = 10
Constructed using one argument constructor, value = 20
Constructed using copy constructor, value = 20
题解
- 首先来分析类,
Member(); // 缺省定义
,用于初始化val
的值;Member(int a);
用于将参数的值赋值到val
;Member(const Member&ans1); // 拷贝构造函数
,我们也是将参数的val
值赋值到val
中;void set(int b); // 设置值
,用于将参数的值赋值到val
中;int get(); // 获得值
,返回val
的值 - 在主函数中,输入组数后,在for循环中在输入一个整数表示用什么方法来构造,然后通过这个整数的判断,用不同的方法,然后不同的输出
代码实现
#include <iostream>
using namespace std;class Member
{
private:int val;
public:Member(); // 缺省定义Member(int a);Member(const Member&ans1); // 拷贝构造函数void set(int b); // 设置值int get(); // 获得值
};Member::Member()
{val = 0;
}Member::Member(int a)
{val = a;
}Member::Member(const Member&ans1)
{val = ans1.val;
}void Member::set(int b)
{val = b;
}int Member::get()
{return val;
}int main()
{int t, i, n, x;cin >> t;for (i = 0; i < t; i++){cin >> n;if (n == 0){Member ans;cout << "Constructed by default, value = " << ans.get() << endl;}else if (n == 1){cin >> x;Member ans(x);cout << "Constructed using one argument constructor, value = " << ans.get() << endl;}else if (n == 2){cin >> x;Member ans1(x); // 输入的参数构造cout << "Constructed using one argument constructor, value = " << ans1.get() << endl;Member ans2(ans1); // 调用拷贝构造函数cout << "Constructed using copy constructor, value = " << ans2.get() << endl;}}return 0;
}
id:51 C.电话号码升位(拷贝构造函数)
题目描述
定义一个电话号码类CTelNumber,包含1个字符指针数据成员,以及构造、析构、打印及拷贝构造函数。
字符指针是用于动态创建一个字符数组,然后保存外来输入的电话号码
构造函数的功能是为对象设置键盘输入的7位电话号码,
拷贝构造函数的功能是用原来7位号码的对象升位为8位号码对象,也就是说拷贝构造的对象是源对象的升级.电话升位的规则是原2、3、4开头的电话号码前面加8,原5、6、7、8开头的前面加2。
注意:电话号码只能全部是数字字符,且与上述情况不符的输入均为非法
输入
测试数据的组数 t
第一个7位号码
第二个7位号码
…
输出
第一个号码升位后的号码
第二个号码升位后的号码
…
如果号码升级不成功,则输出报错信息,具体看示例
输入样例1
3
6545889
3335656
565655
输出样例1
26545889
83335656
Illegal phone number
输入样例2
2
1234567
22a2567
输出样例2
Illegal phone number
Illegal phone number
题解
CTelNumber
类:先定义一个私有的字符型指针,用于存储号码;四个公有的函数,CTelNumber(char *p1); // 构造
,构造函数,用于设置七位电话号码;~CTelNumber(); // 析构
,析构函数,用于释放动态创建的用于存储电话号码的字符指针所指向的空间;void print(); // 打印
,打印函数,用于打印电话号码;CTelNumber(const CTelNumber& p1); // 拷贝构造
,是拷贝构造函数,用于处理在电话号码前添加数字CTelNumber(char *p1);
,构造函数,我们先用srelen
函数计算得到传入的电话号码的字节数,然后为phone
申请的内存空间比得到的字节数多2,一个用来存储后面添加进来的数字,一个用来放字符串结束符\0
,然后使用strncpy
函数将值进行赋值,最后在末尾放结束标志符CTelNumber(const CTelNumber& p1);
拷贝构造函数,首先为phone
申请一段新的内存空间,然后赋值,判断号码的第一位的数字是几,则实行不同的相应操作,操作结束后在字符数组的末尾添加字符串结束符- 首先读入组数,然后我们是用字符数组存储电话号码,所以我们要去掉输入组数后的那个换行符,然后动态创建一个字符指针,输入号码,获取长度,判断其长度是否为7,若不是,则视为非法输入,否则,挨个判断每个元素是否是数字,若不是,记为非法输入,所以我们需要有一个变量判断输入进来的电话号码是否为非法输入,还要判断电话号码的第一位数字不能是019,若输入的号码是正确的,则进行构造初始化,和拷贝构造在开头新添数字,然后输出,最后记得要释放动态创建的内存
犯的错误
修改前的代码中
-
在
CTelNumber
构造函数中,我首先为phone
分配了新的内存,然后立即将phone
指向p1
。这样会导致内存泄漏,因为我无法再访问和删除之前分配的内存。所以应该使用strncpy
函数来复制p1
到phone
。 -
在拷贝构造函数中,我没有为
phone
分配新的内存,但是试图将数据复制到phone
。这将导致未定义的行为,因为我正在写入未分配的内存。所以需要首先为phone
分配新的内存。 -
我之前的的程序没有处理电话号码的长度。如果电话号码的长度不是7,程序可能会出现问题。所以需要添加一些检查来确保电话号码的长度是正确的。
-
且我在判断输入的电话号码是否合法时,及判断输入的第一位数字,没有用到ACSLL的值
代码实现
#include <iostream>
#include <cstring>
using namespace std;class CTelNumber
{
private:char* phone;
public:CTelNumber(char *p1); // 构造~CTelNumber(); // 析构void print(); // 打印CTelNumber(const CTelNumber& p1); // 拷贝构造
};CTelNumber::CTelNumber(char *p1) // 设置7位电话号码
{size_t len = strlen(p1);phone = new char[len + 2]; // 存储'\0'strncpy(phone, p1, len);phone[len] = '\0';
}CTelNumber::~CTelNumber()
{delete[] phone;
}void CTelNumber::print()
{cout << phone << endl;
}CTelNumber::CTelNumber(const CTelNumber& p1)
{int i, len;len = strlen(p1.phone);phone = new char[len + 2]; // 重新分配内存,存储'\0'strncpy(phone, p1.phone, len);if (*phone == '2' || *phone == '3' || *phone == '4') // 234开头{*phone = '8';for (i = 0; i < 7; i++){*(phone + 1 + i) = *(p1.phone + i);}}else{*phone = '2';for (i = 0; i < 7; i++){*(phone + 1 + i) = *(p1.phone + i);}}*(phone + len + 1) = '\0'; // 添加结束字符
}int main()
{int t, i, f, j;char ch;cin >> t; // 组数ch = getchar(); // 舍弃换行符for (i = 0; i < t; i++){f = 0; // 正确char* p = new char[9];cin >> p; // 读取一行输入,最多8个字符和一个结束字符int len = strlen(p); // 获取输入的长度if (len != 7) // 如果输入的长度不是7,标记为非法输入{f = 1;}else{for (j = 0; j < len; j++){if ((*(p + j) - '0') < 0 || (*(p + j) - '9') > 9){f = 1; // 输入不为数字break;}}}if (*p == '0' || *p == '1' || *p == '9') // 如果第一位的数字是019{f = 1; // 错误}if (f == 1) // 非法输入{cout << "Illegal phone number" << endl;}else{CTelNumber pp(p); // 设置7位电话号码CTelNumber p2(pp); // 调用拷贝构造函数p2.print();}delete[] p;}return 0;
}
id:52 D.软件备份(拷贝构造函数)
题目描述
软件作为一种对象也可以用类来描述,软件的属性包括软件名称、类型(分别用O、T和B表示原版、试用版还是备份)、有效截止日期(用CDate类子对象表示)和存储介质(分别用D、H和U表示光盘、磁盘和U盘)等。软件拷贝可通过拷贝构造函数来实现,此时在拷贝构造函数中软件类型改成“B”, 存储介质改为"H",其它不变。试完成该类的拷贝构造、构造和打印(包括从2015年4月7日算起有效期还有多少天,是否过期)成员函数的实现。
当输入软件有效截止日期是0年0月0日,表示无日期限制,为unlimited;当输入日期在2015年4月7日之前,则是过期,表示为expired;如果输入日期在2015年4月7日之后,则显示之后的剩余天数。具体输出信息看输出范例。
附CDate类的实现:
class CDate
{private:int year, month, day;public:CDate(int y, int m, int d);bool isLeapYear();int getYear();int getMonth();int getDay();int getDayofYear();
};CDate::CDate(int y, int m, int d)
{ year = y, month = m,day = d;
}bool CDate::isLeapYear()
{ return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}int CDate::getYear()
{ return year;
}int CDate::getMonth()
{ return month;
}int CDate::getDay()
{ return day;
}int CDate::getDayofYear()
{int i, sum = day;int a[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};if (isLeapYear()){a[2]++;}// 求日期的天数for (i = 0; i < month; i++){sum += a[i];}return sum;
}
输入
测试数据的组数 t第一个软件名称第一个软件类型 第一个软件介质类型 第一个软件有效期年 月 日第二个软件名称第二个软件类型 第二个软件介质类型 第二个软件有效期年 月 日......注意:软件名称最大长度为30;
输入
name: 第一个软件名称type: 第一个软件类型media: 第一个软件介质类型第一个软件2015-4-7后的有效天数name: 第一个软件名称type: backupmedia: hard disk第一个软件2015-4-7后的有效天数......
输入样例1
3
Photoshop_CS5
O D 0 0 0
Audition_3.0
B U 2015 2 3
Visual_Studio_2010
T H 2015 5 5
输出样例1
name:Photoshop_CS5
type:original
media:optical disk
this software has unlimited use
name:Photoshop_CS5
type:backup
media:hard disk
this software has unlimited use
name:Audition_3.0
type:backup
media:USB disk
this software has expired
name:Audition_3.0
type:backup
media:hard disk
this software has expired
name:Visual_Studio_2010
type:trial
media:hard disk
this software is going to be expired in 28 days
name:Visual_Studio_2010
type:backup
media:hard disk
this software is going to be expired in 28 days
输入样例2
2
Photoshop_CS5
O D 2015 4 8
Audition_3.0
B U 2023 4 7
输出样例2
name:Photoshop_CS5
type:original
media:optical disk
this software is going to be expired in 1 days
name:Photoshop_CS5
type:backup
media:hard disk
this software is going to be expired in 1 days
name:Audition_3.0
type:backup
media:USB disk
this software is going to be expired in 2922 days
name:Audition_3.0
type:backup
media:hard disk
this software is going to be expired in 2922 days
题解
CDate
类:定义三个私有变量,年月日,定义六个公有函数,CDate(int y, int m, int d); // 构造函数初始化
;bool isLeapYear(); // 判断是否是闰年
;int getYear(); // 返回年份
;int getMonth();
;int getDay();
;int getDayofYear();
,返回一个整数,这个整数是这个日期前的天数的总和CDate(int y, int m, int d);
,将参数的值传入年月日中bool isLeapYear();
,如果是闰年,返回1,否则,返回0int getYear();
,int getMonth();
和int getDay();
,分别返回调用这个函数的变量的年月日int CDate::getDayofYear();
,题目给出的函数,定义一个存放12个月份的天数的数组,然后把这个月份之前的月份的天数累加,再加上这个月份的天数,得到的结果即为这个日期前所有的月份总和,把值返回Soft
类:定义四个私有变量,软件名称,软件类型,有效日期和存储介质;和四个公有函数,Soft(const Soft &s1); // 软件拷贝
;Soft(char *m, char n, char p, CDate d); // 构造初始化
;void print(); // 打印
和~Soft(); // 析构函数释放内存
Soft::Soft(const Soft &s1) // 拷贝构造函数;
,首先用: dd(s1.dd) // 初始化
来进行对日期的初始化,因为日期不是一个指针,所以可以这样对其赋值,然后计算软件名称的字节数,动态分配这个字节数加1的内存给name
,加1是为了在末尾处放上字符串结束符,然后使用strncpy
函数对其赋值,由于软件名称和存储介质都是单个字符型,所以可以直接使用赋值号对其进行赋值,软件类型改为‘B‘,存储介质改为’H‘Soft::Soft(char *m, char n, char p, CDate d) // 构造
,构造函数和拷贝构造函数大同小异void Soft::print();
,输出函数,按照输出样例,分不同的情况进行不同的输出,注意后面有效天数的年份大于2015年时的计算Soft::~Soft();
,析构函数,释放软件名称内存- 主函数中,进行输入,初始化,拷贝构造,打印,释放内存即可
代码实现
#include <iostream>
#include <cstring>
using namespace std;class CDate
{
private:int year, month, day;public:CDate(int y, int m, int d); // 构造函数初始化bool isLeapYear(); // 判断是否是闰年int getYear(); // 返回年份int getMonth();int getDay();int getDayofYear();
};CDate::CDate(int y, int m, int d)
{year = y;month = m;day = d;
}bool CDate::isLeapYear()
{return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}int CDate::getYear()
{return year;
}int CDate::getMonth()
{return month;
}int CDate::getDay()
{return day;
}int CDate::getDayofYear()
{int i, sum;int a[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};sum = day;if (isLeapYear()) // 如果是闰年{a[2]++; // 有29号}// 求日期的天数for (i = 0; i < month; i++){sum += a[i];}return sum;
}class Soft
{
private:char *name; // 软件名称char type; // 软件类型CDate dd;char media; // 存储介质
public:Soft(const Soft &s1); // 软件拷贝Soft(char *m, char n, char p, CDate d); // 构造初始化void print(); // 打印~Soft(); // 析构函数释放内存
};Soft::Soft(const Soft &s1) // 拷贝构造函数: dd(s1.dd) // 初始化
{int len = strlen(s1.name);name = new char[len + 1];strncpy(name, s1.name, len);type = 'B';media = 'H';name[len] = '\0';
}Soft::Soft(char *m, char n, char p, CDate d) // 构造: dd(d)
{int len = strlen(m);name = new char[len + 1];strncpy(name, m, len);type = n;media = p;name[len] = '\0';
}void Soft::print()
{int t, x, i, sum, n;t = 0; // 未过期cout << "name:" << name << endl;if (type == 'O'){cout << "type:original" << endl;}else if (type == 'B'){cout << "type:backup" << endl;}else if (type == 'T'){cout << "type:trial" << endl;}if (media == 'D'){cout << "media:optical disk" << endl;}else if (media == 'U'){cout << "media:USB disk" << endl;}else if (media == 'H'){cout << "media:hard disk" << endl;}if (dd.getYear() == 0 && dd.getMonth() == 0 && dd.getDay() == 0){t = 2; // 无日期}else if (dd.getYear() < 2015 || (dd.getYear() == 2015 && dd.getMonth() < 4) || (dd.getYear() == 2015 && dd.getMonth() == 4 && dd.getDay() < 7)){t = 1; // 过期}if (t == 2) // 无日期{cout << "this software has unlimited use" << endl;}else if (t == 1) // 过期{cout << "this software has expired" << endl;}else{sum = 0; // 总的天数if (dd.getYear() > 2015){x = dd.getYear() - 2015; // 和15年的差值for (i = 1; i < x; i++){n = 2015 + i;CDate d1(n, dd.getMonth(), dd.getDay());if (d1.isLeapYear()) // 如果是闰年{sum += 366;}else // 平年{sum += 365;}}sum += dd.getDayofYear();cout << "this software is going to be expired in " << sum + 268 << " days" << endl;}else{sum = dd.getDayofYear();cout << "this software is going to be expired in " << sum - 97 << " days" << endl;}}cout << endl;
}Soft::~Soft()
{delete[] name;
}int main()
{int t, i, yy, mm, dd;char *na, ty, me, ch;cin >> t; // 组数ch = getchar();na = new char[31];for (i = 0; i < t; i++){cin >> na >> ty >> me >> yy >> mm >> dd;CDate d(yy, mm, dd); // 初始化日期Soft s(na, ty, me, d); // 初始化软件的属性s.print();Soft s1(s); // 拷贝构造s1.print();}delete[] na;return 0;
}
id:53 E.手机服务(构造+拷贝构造+堆)
题目描述
设计一个类来实现手机的功能。它包含私有属性:号码类型、号码、号码状态、停机日期;包含方法:构造、拷贝构造、打印、停机。
- 号码类型表示用户类别,只用单个字母,A表示机构,B表示企业、C表示个人
- 号码是11位整数,用一个字符串表示
- 号码状态用一个数字表示,1、2、3分别表示在用、未用、停用
- 停机日期是一个日期对象指针,在初始化时该成员指向空,该日期类包含私有属性年月日,以及构造函数和打印函数等
-
构造函数的作用就是接受外来参数,并设置各个属性值,并输出提示信息,看示例输出
-
拷贝构造的作用是复制已有对象的信息,并输出提示信息,看示例输出。
想一下停机日期该如何复制,没有停机如何复制??已经停机又如何复制?? -
打印功能是把对象的所有属性都输出,输出格式看示例
-
停机功能是停用当前号码,参数是停机日期,无返回值,操作是把状态改成停用,并停机日期指针创建为动态对象,并根据参数来设置停机日期,最后输出提示信息,看示例输出
要求:在主函数中实现号码备份的功能,对已有的虚拟手机号的所有信息进行复制,并将号码类型改成D表示备份;将手机号码末尾加字母X
输入
第一行输入t表示有t个号码
第二行输入6个参数,包括号码类型、号码、状态、停机的年、月、日,用空格隔开
依次输入t行
输出
每个示例输出三行,依次输出原号码信息、备份号码信息和原号码停机后的信息
每个示例之间用短划线(四个)分割开,看示例输出
输入样例1
2
A 15712345678 1 2023 1 1
B 13287654321 2 2012 12 12
输出样例1
Construct a new phone 15712345678
类型=机构||号码=15712345678||State=在用
Construct a copy of phone 15712345678
类型=备份||号码=15712345678X||State=在用
Stop the phone 15712345678
类型=机构||号码=15712345678||State=停用||停机日期=2023.1.1
----
Construct a new phone 13287654321
类型=企业||号码=13287654321||State=未用
Construct a copy of phone 13287654321
类型=备份||号码=13287654321X||State=未用
Stop the phone 13287654321
类型=企业||号码=13287654321||State=停用||停机日期=2012.12.12
----
输入样例2
1
C 15674561389 3 2020 1 2
输出样例2
Construct a new phone 15674561389
类型=个人||号码=15674561389||State=停用
Construct a copy of phone 15674561389
类型=备份||号码=15674561389X||State=停用
Stop the phone 15674561389
类型=个人||号码=15674561389||State=停用||停机日期=2020.1.2
----
题解
- Date类:有三个私有变量,分别是年月日;两个公有函数,一个是构造函数,作用是给变量初始化,赋予参数的值,还有一个是打印函数,作用是打印出停机日期
- Phone类:定义三个私有变量,一个是char型的号码类型,一个是字符指针号码,一个是整数型的号码状态,还有一个是Date型的指针表示停机日期;五个公有的函数,一个是构造函数,用于初始化四个变量的值,一个是拷贝构造函数,一个是打印函数,一个是析构函数,还有一个是用于处理停机的函数
- 下面来分别分析各个公有的函数,
Phone(char t, char *n, int s, Date *d); // 构造
,构造函数,用于将参数的值传入四个私有变量中,参数的类型与四个私有变量的类型应该要一致,在这个函数中,因为号码类型是字符型,所以我们可以直接使用赋值号“=”来对号码类型赋值;由于号码的类型是字符指针型,所以我们不能使用赋值号对其进行赋值,因为在析构函数中可能会重复释放相同的一片内存,造成程序崩溃,所以我们可以使用strncpy
函数,其中,为这个变量开辟的空间大小要比需要复制给他的变量的字节数加一,这是因为多出来的一个字节用来存放字符串结束符\0
,计算参数的变量我们可以使用strlen
函数,使用这两个函数我们需要调用头文件cstring
;号码状态是整数型,可以直接使用赋值号来进行复制;因为停机日期是Date类型的指针,如果我们也使用:day(d)
来对day进行赋值的话,这个day也会和被赋值的day指向同一片内存空间,在析构函数中也会被重复释放,所以我们使用day = new Date(*d); // 创建新的Date对象
这种方法来对day进行赋值,这行代码的含义是创建一个新的Date
对象,并将指针d
所指向的Date
对象的内容(即*d
)作为参数传递给构造函数。在这行代码中,假设d
是一个指向Date
对象的指针,*d
则是解引用操作符,表示获取指针d
所指向的Date
对象的值。所以,这行代码的作用是利用指针d
所指向的Date
对象的值来初始化一个新的Date
对象,这样就创建了一个新的Date
对象,其内容与原始对象相同。 Phone(const Phone &p1); // 拷贝构造
,拷贝构造函数,看输出样例可知,我们需要额外的创建一个变量,将第一次用Phone
类型创建的变量赋值到这个新的创建的变量中,然后要改变这个新的创建的变量的号码类型,变为“备份”;然后同样的方法赋值号码,但有所区别的是,这次我们为num开辟的空间要比被拷贝的变量的字节多两个,一个用来存储末尾的X,一个用来存储字符串结束符;同样的方法赋值号码状态和停机日期- 在打印函数中,看输出样例,每个不同的类型的处理的第一行输出都不相同,在打印函数中难以做到条件判断,所以每个类型的第一行输出我们把它放在主函数中输出,然后我们可以在打印函数中处理中间的输出;首先判断号码类型,不同的类型输出不同的中文,然后输出号码状态,由于最后一个打印的停机类型的第一行输出又有所特殊,在主函数中不能直接调用停机日期,所以我们考虑在停机函数中输出第一行,然后最后要输出的停机日期中文也在主函数中输出,日期就调用Date类型的输出函数即可
- 在析构函数中我们需要释放两个变量的内存,一个是num,一个是day
- 在停机函数中,我们需要将号码状态改为停机,然后输出最后一个停机的第一行输出
- 在主函数中,我们先输入有多少个号码,然后处理最后一个回车符,因为后一个是一个字符型输入;号码也是定义为字符型指针,动态创建内存,记得最后释放;最后就是输入和一些初始化和输出
遇到的问题
- 不知道停机函数如何实现,拷贝函数在数组末尾加X
- 使用
:day(d)
初始化,导致后面的析构函数重复释放内存 - 忘记在字符串末尾添加结束符
- 输出函数过于混乱
代码实现
#include <iostream>
#include <cstring>
using namespace std;class Date
{
private:int year;int month;int day;public:Date(int y, int m, int d); // 构造函数void print(); // 打印函数
};Date::Date(int y, int m, int d) // 构造初始化
{year = y;month = m;day = d;
}void Date::print()
{cout << year << "." << month << "." << day << endl;;
}class Phone
{
private:char type; // 号码类型char *num; // 号码int state; // 号码状态Date *day; // 停机日期
public:Phone(char t, char *n, int s, Date *d); // 构造Phone(const Phone &p1); // 拷贝构造void print(); // 打印~Phone(); // 析构释放内存void stop(Date* d); // 停机
};Phone::Phone(char t, char *n, int s, Date *d) // 初始化
{type = t;int len = strlen(n);num = new char[len + 1]; // 额外的空间用于添加'X'strncpy(num, n, len);num[len] = '\0';state = s;day = new Date(*d); // 创建新的Date对象
}Phone::Phone(const Phone &p1)
{type = 'D'; // 表示备份int len = strlen(p1.num);num = new char[len + 2];strncpy(num, p1.num, len);num[len] = 'X';num[len + 1] = '\0';state = p1.state;day = new Date(*(p1.day));
}void Phone::print()
{if (type == 'A') // 输出类型{cout << "类型=机构||号码";}else if (type == 'B'){cout << "类型=企业||号码";}else if (type == 'C'){cout << "类型=个人||号码";}else{cout << "类型=备份||号码";}cout << "=" << num << "||State=";if (state == 1) // 输出号码状态{cout << "在用";}else if (state == 2){cout << "未用";}else{cout << "停用";}
}Phone::~Phone()
{delete[] num; // 释放动态分配的内存delete day;
}void Phone::stop(Date* d)
{state = 3; // 号码状态改为停机cout << "Stop the phone " << num << endl;
}int main()
{int t, i, st, yy, mm, dd;char ty, ch, *num;cin >> t; // t个号码ch = getchar();num = new char[12];for (i = 0; i < t; i++){cin >> ty >> num >> st >> yy >> mm >> dd;Date d1(yy, mm, dd); // 日期初始化Phone p1(ty, num, st, &d1); // 手机初始化cout << "Construct a new phone " << num << endl; // 输出号码p1.print(); // 打印Phone p2(p1); // 拷贝cout << endl << "Construct a copy of phone " << num << endl; // 备份p2.print();cout << endl;p1.stop(&d1); // 停机p1.print();cout << "||停机日期=";d1.print();cout << "----" << endl;}delete[] num;return 0;
}