面向对象程序设计-14-运算符重载

声明

题解包含以下内容:

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

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

【id:79】【20分】A. 分数的加减乘除(运算符重载)

题目描述

Fraction类的基本形式如下:

// 定义Fraction类
class Fraction
{
private:
    int fz, fm;
    int commonDivisor(); // 计算最大公约数
    void contracted(); // 分数化简
public:
    Fraction(int = 0, int = 1);
    Fraction(Fraction&);
    Fraction operator+(Fraction);
    Fraction operator-(Fraction);
    Fraction operator*(Fraction);
    Fraction operator/(Fraction);
    void set(int = 0, int = 1);
    void disply();
};

要求如下:
1.实现Fraction类;common_divisor()和contracted()函数体可为空,不实现具体功能。
2.编写main函数,初始化两个Fraction对象的,计算它们之间的加减乘除。

输入

第1行:依次输入第1个和第2个Fraction对象的分子和分母值。

输出

每行依次分别输出加减乘除计算后的Fraction对象(直接输出分数值,不需要约简)。

样例

输入样例1输出样例1
1 3 2 5fraction=11/15
fraction=-1/15
fraction=2/15
fraction=5/6

Answer

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

class Fraction {
  int fz, fm;

  int commonDivisor() const {
    return std::gcd( abs( fz ), abs( fm ) );
  }
  void contracted() {
    if ( auto gcd_num = commonDivisor();
      gcd_num >= 1 ) {
      fz /= gcd_num;
      fm /= gcd_num;
    }
    if ( fm < 0 && fz > 0 ) {
      fz *= -1;
      fm = abs( fm );
    } else if ( fz < 0 && fm < 0 ) {
      fz = abs( fz );
      fm = abs( fm );
    }
  }

public:
  Fraction( int _fz = 0, int _fm = 1 )
    : fz { _fz }, fm { _fm } {}
  Fraction( const Fraction& lhs ) {
    fz = lhs.fz;
    fm = lhs.fm;
  }
  Fraction operator+( Fraction& lhs ) {
    contracted(); lhs.contracted();
    return Fraction( fz * lhs.fm + fm * lhs.fz, fm * lhs.fm );
  }
  Fraction operator-( Fraction& lhs ) {
    contracted(); lhs.contracted();
    return Fraction( fz * lhs.fm - fm * lhs.fz, fm * lhs.fm );
  }
  Fraction operator*( Fraction& lhs ) {
    contracted(); lhs.contracted();
    return Fraction( fz * lhs.fz, fm * lhs.fm );
  }
  Fraction operator/( Fraction& lhs ) {
    contracted(); lhs.contracted();
    return Fraction( fz * lhs.fm, fm * lhs.fz );
  }
  void set( int _fz = 0, int _fm = 1 ) {
    fz = _fz; fm = _fm;
    contracted();
  }
  void disply() const {
    cout << "fraction="sv << fz << "/" << fm << endl;
  }
  friend istream& operator>>( istream& is, Fraction& lhs ) {
    is >> lhs.fz >> lhs.fm;
    lhs.contracted();
    return is;
  }
};

int main()
{
  Fraction a1, a2;
  cin >> a1 >> a2;
  (a1 + a2).disply();
  (a1 - a2).disply();
  (a1 * a2).disply();
  (a1 / a2).disply();
}

【id:80】【20分】B. 复数的加减乘运算(运算符重载)

题目描述

定义一个复数类,通过重载运算符:+、-、*,实现两个复数之间的各种运算。

class Complex
{
private:
    float real, image;
public:
    Complex(float x = 0, float y = 0);
    friend Complex operator+(Complex&, Complex&);
    friend Complex operator-(Complex&, Complex&);
    friend Complex operator*(Complex&, Complex&);
    void show();
};

要求如下:
1.实现Complex类;
2.编写main函数,初始化两个Complex对象,计算它们之间的加减乘,并输出结果。
复数相乘的运算规则
设z1=a+bi,z2=c+di(a、b、c、d∈R)是任意两个复数,那么它们的积(a+bi)(c+di)=(ac-bd)+(bc+ad)i.

输入

第1行:输入两个数值,分别为第一个Complex对象的实部和虚部。
第2行:输入两个数值,分别为第二个Complex对象的实部和虚部。

输出

第1行:两个Complex对象相加后的输出结果。
第2行:两个Complex对象相减后的输出结果。
第3行:两个Complex对象相乘后的输出结果。

样例

输入样例1输出样例1
10 20
50 40
Real=60 Image=60
Real=-40 Image=-20
Real=-300 Image=1400

Answer

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

class Complex {
  double real, image;

public:
  Complex( double x = {}, double y = {} )
    : real { x }, image { y } {}
  friend Complex operator+( const Complex& a, const Complex& b ) {
    return Complex( a.real + b.real, a.image + b.image );
  }
  friend Complex operator-( const Complex& a, const Complex& b ) {
    return Complex( a.real - b.real, a.image - b.image );
  }
  friend Complex operator*( const Complex& a, const Complex& b ) {
    return Complex( a.real * b.real - a.image * b.image, a.real * b.image + a.image * b.real );
  }
  void show() const {
    cout << fixed << setprecision(0) << "Real="sv << real << " Image="sv << image << endl;
  }
  friend istream& operator>>( istream& is, Complex& cc ) {
    return is >> cc.real >> cc.image;
  }
};

int main()
{
  Complex c1, c2;
  cin >> c1 >> c2;
  (c1 + c2).show();
  (c1 - c2).show();
  (c1 * c2).show();
}

【id:94】【20分】C. 向量的加减(运算符重载)

题目描述

设向量X=(x1,x2,…,xn)和Y=(y1,y2…,yn),它们之间的加、减分别定义为:
X+Y=(x1+y1,x2+y2,…,xn+yn)
X-Y=(x1-y1,x2-y2,…,xn-yn)
编程序定义向量类Vector ,重载运算符“+”、“-”,实现向量之间的加、减运算;并编写print函数作为向量的输出操作。
Vector类的基本形式如下:

class Vector
{
private:
    int vec[5];
public:
    Vector(int v[]);
    Vector();
    Vector(const Vector& obj);
    Vector operator +(const Vector& obj);
    Vector operator -(const Vector& obj);
    void print();
};

要求如下:
1.实现Vector类;
2.编写main函数,初始化两个Vector对象的,计算它们之间的加减,并输出结果。

输入

第1行:输入5个int类型的值,初始化第一个Vector对象。
第2行: 输入5个int类型的值,初始化第二个Vector对象。

输出

第1行:2个Vector对象相加后的输出结果。
第2行:2个Vector对象相减后的输出结果。

样例

输入样例1输出样例1
-4 1 0 10 5
-11 8 10 17 -6
-15 9 10 27 -1
7 -7 -10 -7 11

Answer

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

class Vector {
  std::array<int, 5> vec;

public:
  explicit Vector( std::array<int, 5> v )
    : vec { move( v ) } {}
  Vector() {}
  Vector( const Vector& obj ) : Vector( obj.vec ) {}
  Vector operator+( const Vector& obj ) const {
    Vector ret = *this;
    for ( size_t i = 0; i < ret.vec.size(); ++i )
      ret.vec[i] += obj.vec[i];
    return ret;
  }
  Vector operator-( const Vector& obj ) const {
    Vector ret = *this;
    for ( size_t i = 0; i < ret.vec.size(); ++i )
      ret.vec[i] -= obj.vec[i];
    return ret;
  }
  void print() const {
    for ( int e : vec )
      cout << e << ' ';
    cout << endl;
  }
  friend istream& operator>>( istream& is, Vector& v ) {
    for ( auto& e : v.vec )
      is >> e;
    return is;
  }
};

int main()
{
  Vector v1, v2;
  cin >> v1 >> v2;
  ( v1 + v2 ).print();
  ( v1 - v2 ).print();
}

【id:83】【20分】D. 矩阵相乘(运算符重载)

题目描述

定义一个矩阵类MyMatrix,并且在类中进行运算符重定义,用*实现矩阵相乘。要求必须对运算符进行重载,如果用函数如multiply(matrix,matrix)去实现矩阵之间的运算一律记0分。

必须包含以下析构函数,其中n是矩阵的阶数,data是存放矩阵数据的二维动态数组:

MyMatrix::~MyMatrix() { // 释放空间 for (int i = 0; i < n; i++) { delete[] data[i]; } delete[] data; }

输入

第一行输入所需要的矩阵个数c;
第二行输入矩阵的阶数n,即矩阵是一个n*n的矩阵;
第三行开始依次输入c个矩阵.

输出

c个矩阵相乘的结果

样例

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

Answer

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

class MyMatrix {
  int **data;
  size_t size;

  void kill_data() {
    if ( data != nullptr ) {
      for ( size_t i = 0; i < size; ++i )
        delete[] data[i];
      delete[] data;
    } else size = 0;
  }

public:
  MyMatrix() : data { nullptr }, size {} {}
  MyMatrix( size_t s ) : MyMatrix() {
    data = new int*[s] {};
    for ( size_t i = 0; i < s; ++i )
      data[i] = new int[s] {};
    size = s;
  }
  MyMatrix( const MyMatrix& other ) : MyMatrix() {
    data = new int*[other.size];
    for ( size_t i = 0; i < other.size; ++i ) {
      data[i] = new int[other.size] {};
      memcpy( data[i], other.data[i], other.size * sizeof( int ) );
    }
    size = other.size;
  }
  MyMatrix( MyMatrix&& rhs ) : MyMatrix() {
    using std::swap;
    swap( data, rhs.data );
    swap( size, rhs.size );
  }
  ~MyMatrix() {
    kill_data();
  }
  MyMatrix operator*( const MyMatrix& other ) {
    MyMatrix ret( this->size );
    for ( size_t i = 0; i < size; ++i ) {
      memset( ret.data[i], 0, ret.size * sizeof( int ) );
      for ( size_t ii = 0; ii < size; ++ii ) {
        for ( size_t iii = 0; iii < size; ++iii )
          ret.data[i][ii] += data[i][iii] * other.data[iii][ii];
      }
    }
    return ret;
  }
  MyMatrix& operator=( const MyMatrix& other ) {
    if ( other.size == 0 )
      return *this;
    kill_data();
    data = new int*[other.size];
    for ( size_t i = 0; i < other.size; ++i ) {
      data[i] = new int[other.size] {};
      memcpy( data[i], other.data, other.size * sizeof( int ) );
    }
    size = other.size;
    return *this;
  }
  MyMatrix& operator=( MyMatrix&& rhs ) {
    using std::swap;
    swap( data, rhs.data );
    swap( size, rhs.size );
    return *this;
  }
  friend istream& operator>>( istream& is, MyMatrix& m ) {
    for ( size_t i = 0; i < m.size; ++i ) {
      for ( size_t ii = 0; ii < m.size; ++ii )
        is >> m.data[i][ii];
    }
    return is;
  }
  friend ostream& operator<<( ostream& os, const MyMatrix& m ) {
    for ( size_t i = 0; i < m.size; ++i ) {
      for ( size_t ii = 0; ii < m.size; ++ii )
        os << m.data[i][ii] << ( ii < m.size - 1 ? " " : "" );
      os << ( i < m.size - 1 ? "\n" : "" );
    }
    return os;
  }
};

int main()
{
  size_t c {}, n {};
  cin >> c >> n;
  --c;
  MyMatrix ret( n );
  cin >> ret;
  while ( c-- ) {
    MyMatrix tmp( n );
      cin >> tmp;
    ret = ret * tmp;
  }
  cout << ret << endl;
}

【id:342】【20分】E. 最小生日差值计算(运算符重载)

题目描述

定义一个学生类Student,包含该学生的姓名、出生年、月、日 ,重定义 “-”号实现两个学生之间相差多少天的比较。并利用重载的“-”运算符,求所有学生中年龄相差最小的两个人的名字以及相差天数。

输入

第一行:输入所需要输入的学生个数;
第二行开始,依次输入每个学生的姓名、出生年、月、日。

输出

输出年龄相差最小的两个人的名字以及相差天数,名字的输出顺序按输入的先后,天数大于等于0。

样例

输入样例1输出样例1
3
Tom 1995 1 1
Joe 1995 2 28
Jimmy 1996 1 8
Tom和Joe年龄相差最小,为58天。

Answer

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

class Date {
  int32_t year;
  int16_t month, day;

  static constexpr int16_t base_year = 1970;
  static constexpr std::array<int8_t, 12> months = {
    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  };

  static bool is_leap( int yy ) {
    return (yy % 4 == 0 && yy % 100 != 0) || yy % 400 == 0;
  }
  int count() const {// 返回当前日期是今年第几天
    return accumulate( months.begin(), months.begin() + (month - 1), day ) + (month > 2 ? is_leap(year) : 0);
  }

public:
  Date( int32_t yy, int16_t mm, int16_t dd )
    : year { yy }, month { mm }, day { dd } {}
  Date() : Date( {}, {}, {} ) {}
  int32_t operator-( const Date& d ) const {
    int32_t this_days = count(), d_days = d.count();

    for ( int32_t i = base_year; i < year; ++i )
      this_days += 365 + is_leap( i );
    for ( int32_t i = base_year; i < d.year; ++i )
      d_days += 365 + is_leap( i );

    return this_days - d_days;
  }
  auto operator<=>( const Date& d ) const {
    if ( d.year == year )
      if ( d.month == month )
        return d.day <=> day;
      else return d.month <=> month;
    else return d.year <=> year;
  }
  friend istream& operator>>( istream& is, Date& d ) {
    return is >> d.year >> d.month >> d.day;
  }
};

class Student {
  string name;
  Date birthday;

public:
  Student( string nm, Date birth )
    : name { move( nm ) }, birthday { move( birth ) } {}
  Student() : Student( {}, {} ) {}
  int operator-( const Student& s ) const {
    return birthday - s.birthday;
  }
  const string& get_name() const { return name; }
  auto operator<=>( const Student& s ) const {
    return birthday <=> s.birthday;
  }
  friend istream& operator>>( istream& is, Student& s ) {
    return is >> s.name >> s.birthday;
  }
};

int main()
{
#ifdef _WIN32
  system( "chcp 65001" );
#endif
  size_t num {}; cin >> num;
  vector<Student> students;
  unordered_map<string, size_t> input_order;
  for ( size_t i = 0; i < num; ++i ) {
    Student s; cin >> s;
    input_order.insert( make_pair( s.get_name(), i ) );
    students.push_back( move( s ) );
  }
  sort( students.begin(), students.end() );
  auto stu_pair = make_pair( students.begin(), students.begin() );
  int32_t diff = INT32_MAX;
  for ( auto iter = students.begin() + 1; iter != students.end(); ++iter ) {
    if ( auto tmp_diff = abs( *iter - *prev( iter ) );
         tmp_diff < diff ) {
      tie( stu_pair.first, stu_pair.second, diff ) = make_tuple( prev( iter ), iter, tmp_diff );
    }
  }
  if ( input_order[stu_pair.first->get_name()] > input_order[stu_pair.second->get_name()] ) {
    using std::swap;
    swap( stu_pair.first, stu_pair.second );
  }
  cout << stu_pair.first->get_name() << "和"
    << stu_pair.second->get_name() << "年龄相差最小,为"
    << diff << "天。\n";
}
<think>好的,我需要回答用户关于Python面向对象编程中运算符重载的问题,特别是参考他们提供的头歌教程相关内容。首先,我得理清用户的需求,他们可能想了解运算符重载的基本概念、如何实现,以及具体的示例。 根据用户提供的引用,特别是引用[2]中的Vector类示例,我应该先解释运算符重载的作用,即允许自定义类对象支持内置运算符,如加减乘除等。然后,需要说明在Python中这是通过定义特殊方法如__add__、__sub__等来实现的。 接下来,我需要覆盖常见的运算符及其对应的方法,比如加法对应__add__,减法对应__sub__,比较运算符如<=对应__le__等。同时,用户提到的头歌教程中的练习要求重载%、<=、-三种运算符,所以需要具体说明这些操作的方法名称和实现方式。 另外,必须强调运算符重载的注意事项,比如不能重载不存在的运算符,要保持运算的合理性和一致性,避免滥用导致代码可读性下降。同时,可以给出一个综合示例,比如Test1和Test2类的实现,展示如何重载%、<=和-运算符,这符合引用[3]中的编程要求。 用户可能还希望了解运算符重载的实际应用场景,例如在科学计算中创建向量或矩阵类,或者在游戏开发中处理坐标变换等。这部分可以结合引用中的例子,说明如何使自定义对象的行为更直观。 最后,按照用户的要求生成相关问题,这些问题应该覆盖基本概念、实现方法、注意事项和应用场景,帮助用户进一步深入学习。需要确保问题具体且有针对性,比如如何实现特定运算符重载,或者讨论设计时的注意事项。</think>### Python面向对象编程中的运算符重载详解 运算符重载允许开发者赋予自定义类对象使用Python内置运算符(如`+`, `-`, `%`, `<=`等)的能力。通过定义类中的特殊方法(如`__add__`、`__sub__`),可以控制运算符在对象间的行为逻辑[^1]。 --- #### 一、运算符重载的核心机制 1. **方法命名规则** 每个运算符对应一个以双下划线包裹的特定方法名。例如: - `+` → `__add__()` - `-` → `__sub__()` - `<=` → `__le__()` - `%` → `__mod__()` 2. **实现步骤** 在类中定义对应方法,并通过`self`和`other`参数操作对象属性: ```python class Vector: def __init__(self, x, y): self.x = x self.y = y # 重载加法运算符 def __add__(self, other): return Vector(self.x + other.x, self.y + other.y) ``` --- #### 二、头歌教程案例解析 假设需在`Test1`类中重载`%`、`<=`、`-`运算符: ```python class Test1: def __init__(self, value): self.value = value # 重载减法运算符 def __sub__(self, other): return Test1(self.value - other.value) # 重载小于等于运算符 def __le__(self, other): return self.value <= other.value # 重载取模运算符 def __mod__(self, other): return Test1(self.value % other.value) def __repr__(self): return f"Test1({self.value})" ``` **使用示例**: ```python a = Test1(10) b = Test1(3) print(a - b) # 输出: Test1(7) print(a % b) # 输出: Test1(1) print(a <= b) # 输出: False ``` --- #### 三、关键注意事项 1. **类型一致性** 需处理`other`参数是否为同类实例,避免类型错误: ```python def __add__(self, other): if not isinstance(other, Vector): raise TypeError("操作数类型必须为Vector") return Vector(self.x + other.x, self.y + other.y) ``` 2. **不可重载限制** Python不允许重载不存在的运算符(如`++`),仅支持预定义符号[^3]。 3. **语义合理性** 确保重载后的运算符逻辑符合直觉(如`+`不应实现减法功能)。 --- #### 四、典型应用场景 1. **数学对象建模** 如向量、矩阵、复数等类型的运算。 2. **数据封装增强** 简化自定义数据结构的操作(如链表合并用`+`实现)。 3. **领域特定语言(DSL)** 在框架中创建更贴近业务逻辑的语法。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值