01 复数类
01 复数类
作者:abnb250/山中鹤鸣
博客:https://www.cnblogs.com/abnb250
交流群:1062464078
点击返回目录
前情提要
这一节实现一个 Complex 类,覆盖四则运算、+= 系列、共轭、模长、比较、流输入输出,重点是运算符重载的形态与返回值约定。
注释版主要盯三处:
operator*=/operator/= 若把公式内联展开,实部先更新会让虚部算错;
operator== 用 eps 而非 ==,否则浮点误差误判;
operator>> 先读到局部变量再提交,避免第二个数读失败时对象处于半更新状态。
代码(加注释版)
注释解释了两种场景:
- 代码有反直觉痕迹,自然写法就在旁边。
- 代码看起来自然,但背后有隐形决策。
Complex.h
#ifndef COMPLEX_H
#define COMPLEX_H
#include <iostream>
#include <algorithm>
#include <cmath>
class Complex{
private:
double real;
double imag;
public:
Complex(): real(0), imag(0) {}
Complex(double re, double im) : real(re), imag(im) {}
double get_re() const;
double get_im() const;
Complex& set_re(double newre);
Complex& set_im(double newim);
Complex operator+(const Complex& b) const;
Complex operator-(const Complex& b) const;
Complex operator*(const Complex& b) const;
Complex operator/(const Complex& b) const;
Complex operator/(const double& b) const;
Complex& operator+=(const Complex& b);
Complex& operator-=(const Complex& b);
Complex& operator*=(const Complex& b);
Complex& operator/=(const Complex& b);
Complex get_conj() const;
double get_abs() const;
bool operator==(const Complex& b) const;
bool operator!=(const Complex& b) const;
friend Complex operator+(double a, const Complex& b);
friend std::ostream& operator<<(std::ostream& os, const Complex& a);
friend std::istream& operator>>(std::istream& is, Complex& a);
};
#endif
Complex.cpp
#include "complex.h"
double Complex::get_re() const {
return real;
}
double Complex::get_im() const {
return imag;
}
Complex& Complex::set_re(double newre){
real = newre;
return *this;
}
Complex& Complex::set_im(double newim){
imag = newim;
return *this;
}
Complex Complex::operator+(const Complex& b) const {
Complex res(real + b.real, imag + b.imag);
return res;
}
Complex Complex::operator-(const Complex& b) const {
Complex res(real - b.real, imag - b.imag);
return res;
}
Complex Complex::operator*(const Complex& b) const {
double tmp1, tmp2;
tmp1 = real*b.real - imag*b.imag;
tmp2 = real*b.imag + imag*b.real;
Complex res(tmp1, tmp2);
return res;
}
Complex Complex::operator/(const Complex& b) const {
Complex b_(b.real, -b.imag);
Complex son = *this *b_;
Complex fa = b*b_;
double tmp = fa.real;
if(tmp == 0){
std::cout << "/ is error " << '\n';
return *this;
}
Complex res(son.real/tmp, son.imag/tmp);
return res;
}
Complex Complex::operator/(const double& b) const{
if(b == 0) {
std::cout << "b == 0" << '\n';
return *this;
}
Complex res(real/b, imag/b);
return res;
}
Complex& Complex::operator+=(const Complex& b){
real += b.real;
imag += b.imag;
return *this;
}
Complex& Complex::operator-=(const Complex& b){
real -= b.real;
imag -= b.imag;
return *this;
}
Complex& Complex::operator*=(const Complex& b){
// 不能就地写 real = real*b.real - imag*b.imag; 再 imag = real*b.imag + imag*b.real;
// 第二条会用到已更新的 real,虚部算错
Complex tmp = *this *b;
real = tmp.real;
imag = tmp.imag;
return *this;
}
Complex& Complex::operator/=(const Complex& b){
// 同 operator*=:若内联展开,实部先更新会让虚部计算用到新实部
Complex tmp = *this /b;
real = tmp.real;
imag = tmp.imag;
return *this;
}
Complex Complex::get_conj() const{
return Complex(real, -imag);
}
double Complex::get_abs() const{
return std::sqrt(real*real + imag*imag);
}
bool Complex::operator==(const Complex& b) const{
// 不能改成 real == b.real && imag == b.imag,浮点误差会让数学相等的值判为不等
double eps = 1e-9;
if(std::abs(real - b.real) > eps) return false;
if(std::abs(imag - b.imag) > eps) return false;
return true;
}
bool Complex::operator!=(const Complex& b) const{
if(*this == b) return false;
return true;
}
Complex operator+(double a, const Complex& b){
Complex tmp(a+b.real, b.imag);
return tmp;
}
std::ostream& operator<<(std::ostream& os, const Complex& a){
if(a.real != 0 && a.imag != 0){
if(a.imag > 0)
os << a.real << '+' << a.imag << 'i';
else
os << a.real << a.imag << 'i';
return os;
}
if(a.real == 0 && a.imag != 0){
os << a.imag << 'i';
return os;
}
if(a.real != 0 && a.imag == 0){
os << a.real;
return os;
}
if(a.real == 0 && a.imag == 0){
os << 0;
return os;
}
return os;
}
std::istream& operator>>(std::istream& is, Complex& a){
double re, im;
// 不能直接 is >> a.real >> a.imag,第二个读取失败时 a 的 real 已改、imag 未改
if(is >> re >> im){
a.real = re;
a.imag = im;
}
return is;
}
/*
我要这天再遮不住我眼,我要这地再埋不住我心。
交流群:1062464078
*/

浙公网安备 33010602011771号