C++_第八周做题总结

id:45 A.Equation(类与对象+构造)

题目描述

建立一个类Equation,表达方程ax2+bx+c=0。类中至少包含以下方法:

  1. 无参构造(abc默认值为1.0、1.0、0)与有参构造函数,用于初始化a、b、c的值;

  2. set方法,用于修改a、b、c的值

  3. 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);用于将参数的值赋值到valMember(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,若输入的号码是正确的,则进行构造初始化,和拷贝构造在开头新添数字,然后输出,最后记得要释放动态创建的内存

犯的错误

修改前的代码中

  1. CTelNumber 构造函数中,我首先为 phone 分配了新的内存,然后立即将 phone 指向 p1。这样会导致内存泄漏,因为我无法再访问和删除之前分配的内存。所以应该使用 strncpy 函数来复制 p1phone

  2. 在拷贝构造函数中,我没有为 phone 分配新的内存,但是试图将数据复制到 phone。这将导致未定义的行为,因为我正在写入未分配的内存。所以需要首先为 phone 分配新的内存。

  3. 我之前的的程序没有处理电话号码的长度。如果电话号码的长度不是7,程序可能会出现问题。所以需要添加一些检查来确保电话号码的长度是正确的。

  4. 且我在判断输入的电话号码是否合法时,及判断输入的第一位数字,没有用到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: backup

media: 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,否则,返回0
  • int 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.手机服务(构造+拷贝构造+堆)

题目描述

设计一个类来实现手机的功能。它包含私有属性:号码类型、号码、号码状态、停机日期;包含方法:构造、拷贝构造、打印、停机。

  1. 号码类型表示用户类别,只用单个字母,A表示机构,B表示企业、C表示个人
  2. 号码是11位整数,用一个字符串表示
  3. 号码状态用一个数字表示,1、2、3分别表示在用、未用、停用
  4. 停机日期是一个日期对象指针,在初始化时该成员指向空,该日期类包含私有属性年月日,以及构造函数和打印函数等

  1. 构造函数的作用就是接受外来参数,并设置各个属性值,并输出提示信息,看示例输出

  2. 拷贝构造的作用是复制已有对象的信息,并输出提示信息,看示例输出。
    想一下停机日期该如何复制,没有停机如何复制??已经停机又如何复制??

  3. 打印功能是把对象的所有属性都输出,输出格式看示例

  4. 停机功能是停用当前号码,参数是停机日期,无返回值,操作是把状态改成停用,并停机日期指针创建为动态对象,并根据参数来设置停机日期,最后输出提示信息,看示例输出


要求:在主函数中实现号码备份的功能,对已有的虚拟手机号的所有信息进行复制,并将号码类型改成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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/571880.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【AI学习】Transformer的Token嵌入表示为什么那么长

有朋友问&#xff0c;BERT等大模型的参数量怎么计算的&#xff1f;这个问题&#xff0c;李沐在BERT那篇论文中讲过&#xff0c;主要包括几部分。1、词嵌入&#xff1a;token数量乘以token表示的向量长度&#xff0c;就是 VH&#xff1b;2、注意力计算没有参数&#xff0c;只计算…

MT2041 三角形的个数

思路&#xff1a;找规律&#xff0c;推公式 4等分&#xff1a; 头朝上的三角形&#xff1a; 边长为1&#xff1a;1234s1&#xff1b; 边长为2&#xff1a;123s2&#xff1b; 边长为3&#xff1a;12s3&#xff1b; 边长为4&#xff1a;1s4&#xff1b; 即si12...n-i1(n-i2)*(n-i…

STM32玩转物联网实战篇:5.ESP8266 WIFI模块MQTT通信示例详解

1、准备开发板 开发板功能区分布图 开发板俯视图 2、实验讲解 在之前的章节中&#xff0c;已经讲解过了MQTT的通讯原理和组包过程&#xff0c;现在开始手把手的教大家用代码来实现连接MQTT平台以及数据的交互&#xff0c;实际上这篇文章已经拖更接近两年了&#xff0c;非常…

VS2019中配置C++ OpenCV 4.5.4完整指南

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的在读研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三…

基于STM32的报警器

参考前面的内容&#xff1a;STM32点灯大师&#xff08;中断法&#xff09;-CSDN博客 同样是使用中断的方式触发警报 一、GPIO口配置起来 二、代码 打开gpio.c 重写虚函数&#xff0c;实现我们想要的功能 -----------------------------------------------------------------…

变频器基础原理

文章目录 0. 基本知识1.三相的电压之和为02.正弦交流相量的相量表示法(相量只是表示正弦量&#xff0c;而不等于正弦量 &#xff1b;只有正弦量才能用相量表示)引入相量表示法目的:一种正弦量的产生方式:正弦量的相量表示&#xff0c;使用欧拉公式表示复数 3.用复数表示正弦量&…

Redis入门到通关之Redis网络模型-用户空间和内核态空间

文章目录 欢迎来到 请回答1024 的博客 &#x1f353;&#x1f353;&#x1f353;欢迎来到 请回答1024的博客 关于博主&#xff1a; 我是 请回答1024&#xff0c;一个追求数学与计算的边界、时间与空间的平衡&#xff0c;0与1的延伸的后端开发者。 博客特色&#xff1a; 在我的…

25考研数学可以全程跟张宇吗?

先说结论&#xff1a;25可以全程跟张宇。除了这三种情况。 总的来说&#xff0c;张宇的知识点是全的&#xff0c;不需要担心漏知识点、漏经典方法。不单高数&#xff0c;线代概率也是这样。 但是&#xff0c;老师讲得好&#xff0c;不能保证你上岸。 如果遇到这三种情况&…

java银行存取款程序设计

银行存取款的流程是人们非常熟悉的事情&#xff0c;用户可在银行对自己的资金账户进行存款、取款、查询余额等操作&#xff0c;极大的便利了人民群众对资金的管理。 本任务要求&#xff0c;使用所学知识编写一个银行存取款程序&#xff0c;实现存取款功能。编写一个帐户类实现…

LeetCode //C - 38. Count and Say Medium Topics Companies

38. Count and Say The count-and-say sequence is a sequence of digit strings defined by the recursive formula: countAndSay(1) “1”countAndSay(n) is the way you would “say” the digit string from countAndSay(n-1), which is then converted into a differen…

StrongSORT——基于DeepSORT,提高多目标跟踪的准确性和鲁棒性

1、概述 1.1 DeepSORT DeepSORT算法是在SORT基础上发展起来的一种多目标跟踪算法。SORT算法结合了目标检测器和跟踪器&#xff0c;其中跟踪器的核心是卡尔曼滤波和匈牙利算法。 卡尔曼滤波用于预测目标在下一帧的位置和状态而匈牙利算法则用于将预测状态与实际检测结果进行最…

Linksys RE7000 “AccessControlList ”命令执行漏洞(CVE-2024-25852 )

声明&#xff1a; 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 简介 Linksys RE7000 是由 Linksys 公司生产的一款 Wi-F…

Netty学习——实战篇5 Netty 心跳监测/WebSocket长连接编程 备份

1 心跳监测 MyServer.java public class MyServer {public static void main(String[] args) {NioEventLoopGroup bossGroup new NioEventLoopGroup(1);NioEventLoopGroup workerGroup new NioEventLoopGroup();try {ServerBootstrap serverBootstrap new ServerBootstrap…

DevOps文化对团队有何影响?

DevOps文化对团队有很多积极影响&#xff0c;包括提高团队效率、促进沟通与协作、提高产品质量和推动创新等方面。然而&#xff0c;实施DevOps文化也需要一定的挑战&#xff0c;如改变团队成员的观念、引入新的工具和流程等。因此&#xff0c;团队需要充分了解DevOps文化的价值…

【Ant-Desgin-React 穿梭框】表格穿梭框,树穿梭框的用法

Antd Desgin 穿梭框 普通用法高级用法-表格穿梭框组件高级用法-树穿梭框组件 普通用法 /* eslint-disable no-unused-vars */ import React, { useEffect, useState } from react import { Space, Transfer } from antd// Antd的穿梭框组件Mock数据 const mockData Array.fro…

CJSON工具类

4.4.3.CJSON工具类 OpenResty提供了一个cjson的模块用来处理JSON的序列化和反序列化。 官方地址&#xff1a; https://github.com/openresty/lua-cjson/ 1&#xff09;引入cjson模块&#xff1a; local cjson require "cjson"2&#xff09;序列化&#xff1a; …

记录海豚调度器删除工作流实例失败的解决办法(DolphinScheduler的WebUI删除失败)

本博客记录以下问题解决办法&#xff1a;使用dolphinscheduler的WebUI运行工作流后出现内存占用过高导致的任务阻塞问题&#xff0c;并且在删除工作流实例时总是报错无法删除 解决步骤 在前端页面无法删除&#xff0c;于是搜索资料&#xff0c;发现可以登录数据库进行工作流实…

Day05-docker-compose与私有仓库

Day05-docker-compose与私有仓库 3.4 Docker Compose1&#xff09;compose极速上手指南案例28-初步上手docker-compose2&#xff09;compose文件的常用指令3&#xff09;案例29-docker-compose部署kodexp5&#xff09;小结 3.5 docker镜像仓库之registry仓库1&#xff09;仓库选…

Qt中常用对话框

Qt中的对话框&#xff08;QDialog&#xff09;是用户交互的重要组件&#xff0c;用于向用户提供特定的信息、请求输入、或进行决策。Qt提供了多种标准对话框以及用于自定义对话框的类。以下将详细介绍几种常用对话框的基本使用、使用技巧以及注意事项&#xff0c;并附带C示例代…

SV-7041T IP网络有源音箱 教室广播多媒体音箱(带本地扩音功能)教学广播音箱 办公室背景音乐广播音箱 2.0声道壁挂式网络有源音箱

SV-7041T IP网络有源音箱 教室广播多媒体音箱&#xff08;带本地扩音功能&#xff09; 教学广播音箱 办公室背景音乐广播音箱 一、描述 SV-7041T是深圳锐科达电子有限公司的一款2.0声道壁挂式网络有源音箱&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音源通过自带…