面向对象程序设计-07-构造与拷贝构造

声明

题解包含以下内容:

  • (相对)高级的 C++ 模板及语法技巧
  • 仅适用于 C++20 标准的代码
  • 强烈的个人代码风格和 Modern C++ 范式追求
  • 泛滥的标准库函数

换句话说就是(相较于其他公开题解)更低的查重率和更高的使用门槛;请酌情使用。

【id:45】【20分】A. Equation(类与对象+构造)

题目描述

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

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

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

3、getRoot方法,求出方程的根。

一元二次方程的求根公式如下:

x = − b ± b 2 − 4 a c 2 a x = \frac{-b \pm \sqrt{b^2 - 4ac} } {2a} x=2ab±b24ac

一元二次方程的求解分三种情况,如下:

lab7-A-1

输入

输入测试数据的组数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位

}

样例

输入样例1输出样例1
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

Answer

#include <bits/stdc++.h>
using namespace std;

class Equation {
  double a, b, c;

public:
  Equation() : a {}, b {}, c {} {}
  void set( double aa, double bb, double cc ) {
    a = aa; b = bb; c = cc;
  }
  double discriminant() const {
    return pow( b, 2 ) - (4 * a * c);
  }
  string getRoot() const {
    stringstream ss;
    double x1 {}, x2 {};
    if ( const double delta = discriminant();
      delta > 0 ) {
      x1 = ((-b) + sqrt( delta )) / (2 * a);
      x2 = ((-b) - sqrt( delta )) / (2 * a);
      ss << "x1="sv << fixed << setprecision( 2 ) << x1
        << " x2="sv << fixed << setprecision( 2 ) << x2;
    } else if ( delta == 0 ) {
      x1 = ((-b) + sqrt( delta )) / (2 * a);
      ss << "x1=x2="sv << fixed << setprecision( 2 ) << x1;
    } else {
      x1 = (-b) / (2 * a);
      double image = sqrt( -delta ) / (2 * a);
      ss << "x1="sv << fixed << setprecision( 2 ) << x1 << "+"sv << fixed << setprecision( 2 ) << image << "i "sv
        << "x2="sv << fixed << setprecision( 2 ) << x1 << "-"sv << fixed << setprecision( 2 ) << image << "i"sv;
    }
    return ss.str();
  }
  friend istream& operator>>( istream& is, Equation& lhs ) {
    return is >> lhs.a >> lhs.b >> lhs.c;
  }
  friend ostream& operator<<( ostream& os, const Equation& lhs ) {
    return os << lhs.getRoot();
  }
};

int main()
{
  size_t t = 0;
  cin >> t;
  while ( t-- ) {
    Equation tmp;
    cin >> tmp;
    cout << tmp.getRoot() << endl;
  }
}

【id:50】【20分】B. 对象是怎样构造的(拷贝构造函数)

题目描述

某个类包含一个整型数据成员.程序运行时若输入0表示用缺省方式定义一个类对象;输入1及一个整数表示用带一个参数的构造函数构造一个类对象;输入2及一个整数表示构造2个类对象,一个用输入的参数构造,另一个用前一个对象构造。试完成该类的定义和实现。

输入

测试数据的组数 t

第一组数

第二组数

输出

第一个对象构造输出

第二个对象构造输出

样例

输入样例1输出样例1
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

Answer

#include <bits/stdc++.h>
using namespace std;
class Object {
  int member;
public:
  Object() : member {} {
    cout << "Constructed by default, value = 0"sv << endl;
  }
  Object( int mm ) {
    member = mm;
    cout << "Constructed using one argument constructor, value = "sv << mm << endl;
  }
  Object( const Object& lhs ) {
    member = lhs.member;
    cout << "Constructed using copy constructor, value = "sv << lhs.member << endl;
  }
};

int main()
{
  size_t t = 0; cin >> t;
  while ( t-- ) {
    switch ( int order = 0;
             (cin >> order, order) ) {
    case 0: {
      Object tmp {};
    } break;
    case 1: {
      int num; cin >> num;
      Object tmp { num };
    } break;
    case 2: {
      int num; cin >> num;
      Object tmp { num };
      Object another { tmp };
    } break;
    default: break;
    }
  }
}

【id:51】【20分】C. 电话号码升位(拷贝构造函数)

题目描述

定义一个电话号码类CTelNumber,包含1个字符指针数据成员,以及构造、析构、打印及拷贝构造函数。

字符指针是用于动态创建一个字符数组,然后保存外来输入的电话号码

构造函数的功能是为对象设置键盘输入的7位电话号码,

拷贝构造函数的功能是用原来7位号码的对象升位为8位号码对象,也就是说拷贝构造的对象是源对象的升级.电话升位的规则是原2、3、4开头的电话号码前面加8,原5、6、7、8开头的前面加2。

注意:电话号码只能全部是数字字符,且与上述情况不符的输入均为非法

输入

测试数据的组数 t

第一个7位号码

第二个7位号码

输出

第一个号码升位后的号码

第二个号码升位后的号码

如果号码升级不成功,则输出报错信息,具体看示例

样例

输入样例1输出样例1
3
6545889
3335656
565655
26545889
83335656
Illegal phone number
输入样例2输出样例2
2
1234567
22a2567
Illegal phone number
Illegal phone number

Answer

#include <bits/stdc++.h>
using namespace std;

class CTelNumber {
  size_t len;
  char* str;
public:
  CTelNumber()
    : str { nullptr } {}
  CTelNumber( string_view phone_num )
    : CTelNumber() {
    str = new char[phone_num.size() + 1] {};
    len = phone_num.size();
    strcpy( str, phone_num.data() );
  }
  CTelNumber( const CTelNumber& lhs ) {
    str = new char[lhs.len + 2] {};
    strcpy( str + 1, lhs.str );
    if ( lhs.len != 7 ||
         any_of( lhs.str, lhs.str + lhs.len,
           []( int e ) -> bool { return !isdigit( e ); } ) ||
         lhs.str[0] == '0' || lhs.str[0] == '1' || lhs.str[0] == '9' )
      str[0] = '#';
    else if ( lhs.str[0] >= '2' && lhs.str[0] <= '4' )
      str[0] = '8';
    else
      str[0] = '2';
  }
  ~CTelNumber() { delete[] str; }
  friend ostream& operator<<( ostream& os, const CTelNumber& lhs ) {
    if ( lhs.str[0] != '#' )
      return os << lhs.str;
    else return os << "Illegal phone number"sv;
  }
};

int main()
{
  size_t t = 0;
  cin >> t;
  while ( t-- ) {
    string phone_number; cin >> phone_number;
    CTelNumber phone { phone_number };
    cout << CTelNumber { phone } << endl;
  }

  return 0;
}

【id:52】【20分】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输出样例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
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
2
Photoshop_CS5
O D 2015 4 8
Audition_3.0
B U 2023 4 7
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

Answer

#include <bits/stdc++.h>
using namespace std;

class CDate {
  int year, month, day;

public:
  CDate( int y, int m, int d )
    : year { y }, month { m }, day { d } {}
  static bool isLeapYear( int yy ) noexcept {
    return (yy % 4 == 0 && yy % 100 != 0) || yy % 400 == 0;
  }
  bool isLeapYear() const noexcept { return isLeapYear( year ); }
  int getYear() const noexcept { return year; }
  int getMonth() const noexcept { return month; }
  int getDay() const noexcept { return day; }
  int getDayofYear() const {
    int a[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    if ( isLeapYear() )
      a[1]++;
    return accumulate( a, a + month - 1, day );
  }
  bool operator==( const CDate& other ) const {
    if ( year == other.year )
      if ( month == other.month )
        return day == other.day;
      else return month == other.month;
    return year == other.year;
  }
  bool operator<( const CDate& other ) const {
    if ( year == other.year )
      if ( month == other.month )
        return day < other.day;
      else return month < other.month;
    return year < other.year;
  }
  friend istream& operator>>( istream& is, CDate& lhs ) {
    return is >> lhs.year >> lhs.month >> lhs.day;
  }
  friend class Software;
};

class Software {
  char type;
  char media;
  string name;
  CDate ddl;

public:
  Software( char _type, char _media, string_view _name, CDate day )
    : type { _type }, media { _media }, name { _name }, ddl { move( day ) } {
    if ( name.size() > 30 )
      name.resize( 30 );
  }
  Software() : Software( '\0', '\0', ""sv, CDate( 0, 0, 0 ) ) {}
  Software( const Software& lhs )
    : Software( 'B', 'H', lhs.name, lhs.ddl ) {
    if ( name.size() > 30 )
      name.resize( 30 );
  }
  int is_expired() const {
    if ( ddl.year == 0 )
      return -1;
    if ( ddl.year <= 2015 && ddl.month <= 4 && ddl.day < 7 )
      return 0;
    const CDate tmp { 2015, 4, 7 };
    int sum = 0;
    for(int i = 2015; i < ddl.year; i++)
      sum += CDate(i, 12, 31).getDayofYear();
    sum += ddl.getDayofYear();
    return sum - tmp.getDayofYear();
  }
  string print() const {
    stringstream ss;
    ss <<  "name:"sv << name << "\ntype:"sv;
    if ( type == 'O' )
      ss << "original\n"sv;
    else if ( type == 'B' )
      ss << "backup\n"sv;
    else ss << "trial\n"sv;

    ss << "media:";
    if ( media == 'D' )
      ss << "optical disk\n"sv;
    else if ( media == 'H' )
      ss << "hard disk\n"sv;
    else ss << "USB disk\n"sv;

    const auto expired_flag = is_expired();
    if ( expired_flag == -1 )
      ss << "this software has unlimited use\n"sv;
    else if ( expired_flag == 0 )
      ss << "this software has expired\n"sv;
    else
      ss << "this software is going to be expired in "sv
        << expired_flag << " days\n"sv;
    return ss.str();
  }
  friend istream& operator>>( istream& is, Software& lhs ) {
    is >> lhs.name >> lhs.type >> lhs.media >> lhs.ddl;
    if ( lhs.name.size() > 30 )
      lhs.name.resize( 30 );
    return is;
  }
  friend ostream& operator<< (ostream & os, const Software & lhs) {
    return os << lhs.print();
  }
};

int main()
{
  size_t t = 0;
  cin >> t;
  while ( t-- ) {
    Software tmp;
    cin >> tmp;
    cout << tmp << endl
      << Software { tmp } << endl;
  }
}

【id:53】【20分】E. 手机服务(构造+拷贝构造+堆)

题目描述

设计一个类来实现手机的功能。它包含私有属性:号码类型、号码、号码状态、停机日期;包含方法:构造、拷贝构造、打印、停机。
1、号码类型表示用户类别,只用单个字母,A表示机构,B表示企业、C表示个人
2、号码是11位整数,用一个字符串表示
3、号码状态用一个数字表示,1、2、3分别表示在用、未用、停用
4、停机日期是一个日期对象指针,在初始化时该成员指向空,该日期类包含私有属性年月日,以及构造函数和打印函数等
----------------------------------------

5、构造函数的作用就是接受外来参数,并设置各个属性值,并输出提示信息,看示例输出
6、拷贝构造的作用是复制已有对象的信息,并输出提示信息,看示例输出。
想一下停机日期该如何复制,没有停机如何复制??已经停机又如何复制??

7、打印功能是把对象的所有属性都输出,输出格式看示例
8、停机功能是停用当前号码,参数是停机日期,无返回值,操作是把状态改成停用,并停机日期指针创建为动态对象,并根据参数来设置停机日期,最后输出提示信息,看示例输出
-------------------------------------------

要求:在主函数中实现号码备份的功能,对已有的虚拟手机号的所有信息进行复制,并将号码类型改成D表示备份;将手机号码末尾加字母X

输入

第一行输入t表示有t个号码

第二行输入6个参数,包括号码类型、号码、状态、停机的年、月、日,用空格隔开

依次输入t行

输出

每个示例输出三行,依次输出原号码信息、备份号码信息和原号码停机后的信息

每个示例之间用短划线(四个)分割开,看示例输出

样例

输入样例1输出样例1
2
A 15712345678 1 2023 1 1
B 13287654321 2 2012 12 12
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输出样例2
1
C 15674561389 3 2020 1 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
----

Answer

#include <bits/stdc++.h>
using namespace std;

constexpr int inuse = 1;
constexpr int unused = 2;
constexpr int halt = 3;

class CDate {
  int year, month, day;

public:
  CDate( int y, int m, int d )
    : year { y }, month { m }, day { d } {}
  CDate() :CDate( 0, 0, 0 ) {}
  int getYear() const noexcept { return year; }
  int getMonth() const noexcept { return month; }
  int getDay() const noexcept { return day; }
  friend istream& operator>>( istream& is, CDate& lhs ) {
    return is >> lhs.year >> lhs.month >> lhs.day;
  }
};

class Phone {
  string number;
  char type;
  int status;

public:
  Phone( string_view _number, char _type, int _status )
    : number { _number }, type { _type }, status { _status } {}
  Phone() : Phone( ""sv, '\0', unused ) {}
  Phone( const Phone& host )
    : Phone( host.number, host.type, host.status ) {
    cout << "Construct a copy of phone "sv << number << endl;
    cout << "类型=备份||"sv;
    cout << "号码="sv << number << "X"sv;
    switch ( status ) {
    case inuse: {
      cout << "||State=在用"sv << endl;
    } break;
    case unused: {
      cout << "||State=未用"sv << endl;
    } break;
    case halt: {
      cout << "||State=停用"sv << endl;
    } break;
    default: break;
    }
  }
  void set( char _type, string _num, int _status ) {
    cout << "Construct a new phone " << number << endl;
    number = _num;
    type = _type;
    status = _status;
  }
  void print() const {
    switch ( type ) {
    case 'A': {
      cout << "类型=机构||";
    } break;
    case 'B': {
      cout << "类型=企业||";
    } break;
    case 'C': {
      cout << "类型=个人||";
    } break;
    default: break;
    }
    cout << "号码=" << number;
    switch ( status ) {
    case inuse: {
      cout << "||State=在用";
    } break;
    case unused: {
      cout << "||State=未用";
    } break;
    case halt: {
      cout << "||State=停用";
    } break;
    default: break;
    }
  }
  void stop( const CDate& ddl ) {
    cout << "Stop the phone " << number << endl;
    switch ( type ) {
    case 'A': {
      cout << "类型=机构||";
    } break;
    case 'B': {
      cout << "类型=企业||";
    } break;
    case 'C': {
      cout << "类型=个人||";
    } break;
    default: break;
    }
    cout << "号码=" << number << "||State=停用||停机日期=" << ddl.getYear() << "." << ddl.getMonth() << "." << ddl.getDay() << endl;
  }
  friend istream& operator>>( istream& is, Phone& lhs ) {
    is >> lhs.type >> lhs.number >> lhs.status;
    cout << "Construct a new phone " << lhs.number << endl;
    return is;
  }
  friend ostream& operator<<( ostream& os, const Phone& lhs ) {
    lhs.print();
    return os;
  }
};
int main()
{
#if defined(_WIN32) || defined(WIN32)
  system( "chcp 65001" );
#endif
  size_t t;
  cin >> t;
  while ( t-- ) {
    Phone phone; cin >> phone;
    cout << phone << endl;
    Phone another { phone };
    CDate ddl;
    cin >> ddl;
    another.stop( ddl );
    cout << "----" << endl;
  }

  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值