面向对象程序设计-08-静态成员与友元

声明

题解包含以下内容:

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

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

【id:56】【20分】A. 距离计算(友元函数)

题目描述

Point类的基本形式如下:

class Point
{
private:
    double x, y;
public:
    Point(double xx, double yy); // 构造函数
};

请完成如下要求:

1.实现Point类;

2.为Point类增加一个友元函数double Distance(Point &a, Point &b),用于计算两点之间的距离。直接访问Point对象的私有数据进行计算。

3.编写main函数,输入两点坐标值,计算两点之间的距离。

输入

第1行:输入需计算距离的点对的数目

第2行开始,每行依次输入两个点的x和y坐标

输出

每行依次输出一组点对之间的距离(结果直接取整数部分,不四舍五入 )

样例

输入样例1输出样例1
3
1 0 2 1
2 3 2 4
2 2 4 4
1
1
2

Answer

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

class Point {
  double x, y;
public:
  explicit Point( double xx = 0, double yy = 0)
    : x { xx }, y { yy } {}
  friend double Distance( const Point& p1, const Point& p2 ) {
    return sqrt( pow( abs( p1.x - p2.x ), 2 ) + pow( abs( p1.y - p2.y ), 2 ) );
  }
  friend istream& operator>>( istream& is, Point& p ) {
    return is >> p.x >> p.y;
  }
};

int main()
{
  size_t t = 0;
  cin >> t;
  while ( t-- ) {
    Point p1, p2;
    cin >> p1 >> p2;
    cout << static_cast<int>(Distance( p1, p2 )) << endl;
  }
}

【id:57】【20分】B. 银行账户(静态成员与友元函数)

题目描述

银行账户类的基本描述如下:

class Account
{
private:
    static float count; // 账户总余额
    static float interestRate;
    string accno, accname;
    float balance;
public:
    Account(string ac, string na, float ba);
    ~Account();
    void deposit(float amount); // 存款
    void withdraw(float amount); // 取款
    float getBalance(); // 获取账户余额
    void show(); // 显示账户所有基本信息
    static float getCount(); // 获取账户总余额
    static void setInterestRate(float rate); // 设置利率
    static float getInterestRate(); // 获取利率
};

要求如下:

实现该银行账户类

为账户类Account增加一个友元函数,实现账户结息,要求输出结息后的余额(结息余额=账户余额+账户余额*利率)。友元函数声明形式为 friend void update(Account& a);

在main函数中,定义一个Account类型的指针数组,让每个指针指向动态分配的Account对象,并调用成员函数测试存款、取款、显示等函数,再调用友元函数测试进行结息。

大家可以根据实际需求在类内添加其他方法,也可以修改成员函数的参数设置

输入

第1行:利率
第2行:账户数目n
第3行开始,每行依次输入一个账户的“账号”、“姓名”、“余额”、存款数,取款数。

输出

第1行开始,每行输出一个账户的相关信息,包括账号、姓名、存款后的余额、存款后结息余额、取款后余额。

最后一行输出所有账户的余额。

样例

输入样例1输出样例1
0.01
3
201501 张三 10000 1000 2000
201502 李四 20000 2000 4000
201503 王二 80000 4000 6000
201501 张三 11000 11110 9110
201502 李四 22000 22220 18220
201503 王二 84000 84840 78840
106170

Answer

#include <bits/stdc++.h>
using namespace std;
class Account {
  static float count; // 账户总余额
  static float interestRate;
  string accno, accname;
  float balance;
public:
  Account( string ac, string na, float ba )
    : accno { move( ac ) }, accname { move( na ) }, balance { ba } {}
  Account() : Account( {}, {}, 0.0f ) {}
  ~Account() {}
  void deposit( float amount ) {
    if ( amount < 0 )
      return;
    balance += amount;
  }
  void withdraw( float amount ) {
    if ( amount < 0 || amount > balance )
      return;
    balance -= amount;
  }
  float getBalance() const { return balance; }
  void show() {
    cout << fixed << setprecision( 0 ) << balance << endl;
    count += balance;
  }
  static float getCount() { return count; }
  static void setInterestRate( float rate ) { interestRate = rate; }
  static float getInterestRate() { return interestRate; }
  friend istream& operator>>( istream& is, Account& acc ) {
    return is >> acc.accno >> acc.accname >> acc.balance;
  }
  friend ostream& operator<<( ostream& os, const Account& acc ) {
    return os << fixed << setprecision( 0 ) << acc.accno << ' ' << acc.accname << ' ' << acc.balance << ' ';
  }
  friend void update( Account& a ) {
    a.balance = a.balance + a.balance * Account::interestRate;
    cout << fixed << setprecision(0) << a.balance << ' ';
  }
};

float Account::count = {};
float Account::interestRate = {};

int main()
{
  int num {}; float rate;
  cin >> rate >> num;
  Account::setInterestRate( rate );
  auto arr = new Account[num];
  for ( int i = 0; i < num; ++i ) {
    double cash_save {}, cash_withdraw {};
    cin >> arr[i] >> cash_save >> cash_withdraw;
    arr[i].deposit( cash_save );
    cout << arr[i];
    update( arr[i] );
    arr[i].withdraw( cash_withdraw );
    arr[i].show();
  }
  cout << fixed << setprecision( 0 ) << Account::getCount();
}

【id:58】【20分】C. 复数运算(友元函数)

题目描述

复数类的声明如下:

class Complex
{
private:
	double real; // 实部
	double imag; // 虚部
public:
	Complex();
	Complex(double r, double i);
	// 友元函数,复数c1 + c2(二参数对象相加)
	friend Complex addCom(const Complex& c1, const Complex& c2);
	// 友元函数,输出类对象c的有关数据(c为参数对象)
	friend void outCom(const Complex& c);
};

要求如下:

  1. 实现复数类和友元函数addCom和outCom。
  2. 参考addCom函数为复数类增加一个友元函数minusCom,用于实现两个复数的减法
  3. 在main函数中,通过友元函数,实现复数的加减法和复数的输出。

输入

第1行:第1个复数的实部和虚部

第2行:需进行运算的次数,注意:是连续运算。具体结果可参考样例

第3行开始,每行输入运算类型,以及参与运算的复数的实部与虚部。“+”表示复数相加,“-”表示复数相减。

输出

每行输出复数运算后的结果,复数输出格式为“(实部,虚部)”。

样例

输入样例1输出样例1
10 10
3
+ 20 10
- 15 5
+ 5 25
(30,20)
(15,15)
(20,40)

Answer

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

class Complex {
  double real; // 实部
  double imag; // 虚部
public:
  Complex( double r, double i )
    : real { r }, imag { i } {}
  Complex() : Complex( {}, {} ) {}
  // 友元函数,复数c1 + c2(二参数对象相加)
  friend Complex addCom( const Complex& c1, const Complex& c2 ) {
    Complex ret = c1;
    ret.real += c2.real;
    ret.imag += c2.imag;
    return ret;
  }
  friend Complex minusCom( const Complex& c1, const Complex& c2 ) {
    Complex ret = c1;
    ret.real -= c2.real;
    ret.imag -= c2.imag;
    return ret;
  }
    // 友元函数,输出类对象c的有关数据(c为参数对象)
  friend void outCom( const Complex& c ) {
    cout << fixed << setprecision( 0 ) << '(' << c.real << ',' << c.imag << ')' << endl;
  }
  friend istream& operator>>( istream& is, Complex& c ) {
    return is >> c.real >> c.imag;
  }
};

int main()
{
  Complex c1; cin >> c1;
  size_t cal_time {};
  cin >> cal_time;
  while ( cal_time-- ) {
    char op {}; Complex c2;
    cin >> op >> c2;
    if ( op == '+' )
      outCom( (c1 = addCom( c1, c2 )) );
    else outCom( (c1 = minusCom( c1, c2 )) );
  }
}

【id:59】【20分】D. 旅馆顾客统计(静态成员)

题目描述

编写程序,统计某旅馆住宿客人的总数和收入总额。要求输入客人的姓名,输出客人编号(2015+顺序号,顺序号4位,如第1位为0001,第2位为0002,依此类推)、姓名、总人数以及收入总额。总人数和收入总额用静态成员,其他属性采用普通的数据成员。旅馆类声明如下:

class Hotel
{
private:
    static int totalCustNum; // 顾客总人数
    static float totalEarning; // 旅店总收入
    static float rent; // 每个顾客的房租
    char *customerName; // 顾客姓名
    int customerId; // 顾客编号
public:
    // totalCustNum++,customerId按照totalCustNum生成
    Hotel(char* customer);
    ~Hotel(); //记得delete customerName
    void Display(); //相应输出顾客姓名、顾客编号、总人数、总收入
};

输入

第1行:输入旅馆单个顾客房租

第2行开始,依次输入顾客姓名,0表示输入结束, 姓名的最大字符长度为20

输出

每行依次输出顾客信息和当前旅馆信息。包括顾客姓名,顾客编号,旅馆当前总人数,旅馆当前总收入。

样例

输入样例1输出样例1
150
张三 李四 王五 0
张三 20150001 1 150
李四 20150002 2 300
王五 20150003 3 450

Answer

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

class Hotel {
  static int totalCustNum;   // 顾客总人数
  static float totalEarning; // 旅店总收入
  static float rent;         // 每个顾客的房租
  char* customerName;        // 顾客姓名
  int customerId;            // 顾客编号

public:
  // totalCustNum++,customerId按照totalCustNum生成
  explicit Hotel( const char* customer = nullptr ) {
    customerName = new char[strlen( customer ) + 1] {};
    strcpy(customerName, customer);
    customerId = (++totalCustNum) + 20150000;
    totalEarning += rent;
  }
  Hotel( Hotel&& _rhs ) {
    customerName = _rhs.customerName;
    _rhs.customerName = nullptr;
    customerId = _rhs.customerId;
    ++totalCustNum;
  }
  Hotel( const Hotel& ) = delete;
  ~Hotel() { delete[] customerName; --totalCustNum; }
  static void setRent( float _rent ) {
    rent = _rent;
  }
  void Display() {
    string_view name = customerName;
    cout << name << ' ' << customerId << ' ' << totalCustNum << ' ' << totalEarning << endl;
  }
};

int Hotel::totalCustNum = 0;
float Hotel::totalEarning = 0;
float Hotel::rent = 0;

int main()
{
  float hotel_rent = 0;
  cin >> hotel_rent;
  cin.ignore((numeric_limits<streamsize>::max)(), '\n');
  Hotel::setRent( hotel_rent );
  string input; getline( cin, input );
  list<Hotel> customers;
  for ( auto head = input.begin(), tail = head++; *head != '0'; ) {
    if ( head == input.end() )
      break;
    while ( *head != ' ' )
      ++head;
    *head = '\0';
    string_view name { tail, ++head };
    while ( *head == ' ' )
      ++head;
    tail = head++;
    customers.emplace_back( name.data() );
    customers.back().Display();
  }
}

【id:62】【20分】E. 日期时间合并输出(友元函数)

题目描述

已知日期类Date,有属性:年、月、日,其他成员函数根据需要自行编写,注意该类没有输出的成员函数
已知时间类Time,有属性:时、分、秒,其他成员函数根据需要自行编写,注意该类没有输出的成员函数
现在编写一个全局函数把时间和日期的对象合并起来一起输出,
函数原型为:void display(const Date &d, const Time &t)
函数输出要求为:
1、时分秒输出长度固定2位,不足2位补0
2、年份输出长度固定为4位,月和日的输出长度固定2位,不足2位补0
例如2017年3月3日19时5分18秒
则输出为:2017-03-03 19:05:18

程序要求
1、把函数display作为时间类、日期类的友元
2、分别创建一个日期对象和时间对象,保存日期的输入和时间的输入
3、调用display函数实现日期和时间的合并输出

输入

第一行输入t表示有t组示例

接着一行输入三个整数,表示年月日

再接着一行输入三个整数,表示时分秒

依次输入t组示例

输出

每行输出一个日期和时间合并输出结果

输出t行

样例

输入样例1输出样例1
2
2017 3 3
19 5 18
1988 12 8
5 16 4
2017-03-03 19:05:18
1988-12-08 05:16:04

Answer

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

class Date {
  int year, month, day;
  
public:
  explicit Date( int yy = 1970, int mm = 1, int dd = 1 )
    : year { yy }, month { mm }, day { dd } {}
  int getYear() const { return year; }
  int getMonth() const { return month; }
  int getDay() const { return day; }
  friend istream& operator>>( istream& is, Date& d ) {
    return is >> d.year >> d.month >> d.day;
  }
};

class Time {
  int hour, minute, second;

public:
  explicit Time( int hh = 0, int mm = 0, int ss = 0 )
    : hour { hh }, minute { mm }, second { ss } {}
  int getHour() const { return hour; }
  int getMinute() const { return minute; }
  int getSecond() const { return second; }
  friend istream& operator>>( istream& is, Time& t ) {
    return is >> t.hour >> t.minute >> t.second;
  }
};

void display( const Date& d, const Time& t )
{
  cout << setw( 4 ) << d.getYear() << '-'
    << setw( 2 ) << setfill( '0' ) << d.getMonth() << '-'
    << setw( 2 ) << setfill( '0' ) << d.getDay() << ' '
    << setw( 2 ) << setfill( '0' ) << t.getHour() << ':'
    << setw( 2 ) << setfill( '0' ) << t.getMinute() << ':'
    << setw( 2 ) << setfill( '0' ) << t.getSecond()
    << endl;
}

int main()
{
  size_t t {}; cin >> t;
  while ( t-- ) {
    Date d; cin >> d;
    Time t; cin >> t;
    display( d, t );
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值