【C++进阶】Number类完成运算符重载实现


前言

在 C++ 中,运算符重载允许自定义类实现标准运算符(如 +, -, *, / 等)的行为,从而使自定义类的对象可以像内置类型一样进行运算。对于大整数运算或其他自定义数值类型,这种能力尤为重要。本文将探讨如何为 Number 类实现运算符重载,以支持基本的数学运算,如加法、减法、乘法和除法。这些运算符的实现不仅提高了代码的可读性和易用性,还使得 Number 类更加灵活和强大。


位运算的实现

我们需要实现下面这些位运算

Number& operator&=(const Number& other);
Number& operator|=(const Number& other);
Number& operator^=(const Number& other);
Number& operator<<=(size_t shift);
Number& operator>>=(size_t shift);
Number operator~() const;
Number operator<<(size_t shift) const;
Number operator>>(size_t shift) const;

下面为它的实现代码

Number& Number::operator&=(const Number& other)
{
    if (BitSize != other.BitSize)
    {
        throw std::invalid_argument("Bit sizes do not match");
    }

    size_t NeedGroup = (BitSize + 7) / 8;
    for (size_t i = 0; i < NeedGroup; ++i)
    {
        Data[i] &= other.Data[i];
    }

    return *this;
}

Number& Number::operator|=(const Number& other)
{
    if (BitSize != other.BitSize)
    {
        throw std::invalid_argument("Bit sizes do not match");
    }

    size_t NeedGroup = (BitSize + 7) / 8;
    for (size_t i = 0; i < NeedGroup; ++i)
    {
        Data[i] |= other.Data[i];
    }

    return *this;
}

Number& Number::operator^=(const Number& other)
{
    if (BitSize != other.BitSize)
    {
        throw std::invalid_argument("Bit sizes do not match");
    }

    size_t NeedGroup = (BitSize + 7) / 8;
    for (size_t i = 0; i < NeedGroup; ++i)
    {
        Data[i] ^= other.Data[i];
    }

    return *this;
}

Number& Number::operator<<=(size_t shift)
{
    if (shift >= BitSize)
    {
        std::fill_n(Data, (BitSize + 7) / 8, 0);
        return *this;
    }

    size_t byteShift = shift / 8;
    size_t bitShift = shift % 8;

    if (bitShift == 0)
    {
        std::memmove(Data, Data + byteShift, (BitSize + 7) / 8 - byteShift);
        std::fill_n(Data + (BitSize + 7) / 8 - byteShift, byteShift, 0);
    }
    else
    {
        for (size_t i = (BitSize + 7) / 8; i > byteShift; --i)
        {
            Data[i - 1] = (Data[i - 1 - byteShift] << bitShift) |
                (Data[i - 2 - byteShift] >> (8 - bitShift));
        }
        Data[byteShift] = Data[0] << bitShift;
        std::fill_n(Data, byteShift, 0);
    }

    return *this;
}

Number& Number::operator>>=(size_t shift)
{
    if (shift >= BitSize)
    {
        std::fill_n(Data, (BitSize + 7) / 8, 0);
        return *this;
    }

    size_t byteShift = shift / 8;
    size_t bitShift = shift % 8;

    if (bitShift == 0)
    {
        std::memmove(Data, Data + byteShift, (BitSize + 7) / 8 - byteShift);
        std::fill_n(Data + (BitSize + 7) / 8 - byteShift, byteShift, 0);
    }
    else
    {
        for (size_t i = 0; i < (BitSize + 7) / 8 - byteShift - 1; ++i)
        {
            Data[i] = (Data[i + byteShift] >> bitShift) |
                (Data[i + byteShift + 1] << (8 - bitShift));
        }
        Data[(BitSize + 7) / 8 - byteShift - 1] = Data[(BitSize + 7) / 8 - 1] >> bitShift;
        std::fill_n(Data + (BitSize + 7) / 8 - byteShift, byteShift, 0);
    }

    return *this;
}

Number Number::operator~() const
{
    Number result(BitSize);
    size_t NeedGroup = (BitSize + 7) / 8;
    for (size_t i = 0; i < NeedGroup; ++i)
    {
        result.Data[i] = ~Data[i];
    }
    return result;
}

Number Number::operator<<(size_t shift) const
{
    Number result = *this;
    result <<= shift;
    return result;
}

Number Number::operator>>(size_t shift) const
{
    Number result = *this;
    result >>= shift;
    return result;
}

这些位运算操作符重载是为 Number 类实现的,允许对类实例进行位操作,包括按位与、按位或、按位异或、按位取反、左移和右移。以下是每个运算符的详细实现和说明:

  1. operator&=(const Number& other)

功能: 执行按位与运算,并将结果赋值给当前对象。

实现细节:

  • 首先检查 BitSize 是否匹配,以确保两个 Number 对象的位数相同。
  • 遍历所有字节,逐个进行按位与运算 (Data[i] &= other.Data[i])。
  • 操作完成后,将结果存储回 Data 中。
  1. operator|=(const Number& other)

功能: 执行按位或运算,并将结果赋值给当前对象。

实现细节:

  • 首先检查 BitSize 是否匹配。
  • 遍历所有字节,逐个进行按位或运算 (Data[i] |= other.Data[i])。
  • 将结果存储回 Data 中。
  1. operator^=(const Number& other)

功能: 执行按位异或运算,并将结果赋值给当前对象。

实现细节:

  • 检查 BitSize 是否匹配。
  • 遍历所有字节,逐个进行按位异或运算 (Data[i] ^= other.Data[i])。
  • 将结果存储回 Data 中。
  1. operator<<=(size_t shift)

功能: 执行按位左移运算,并将结果赋值给当前对象。

实现细节:

  • 如果移位量大于等于 BitSize,则将所有数据置为 0。
  • 计算字节移位和位移位的量 (byteShiftbitShift)。
  • 对于位移量为 0 的情况,使用 std::memmove 将字节左移,并填充移出的字节位置。
  • 对于非 0 位移量,逐字节处理左移,考虑到移出和移入的位。
  1. operator>>=(size_t shift)

功能: 执行按位右移运算,并将结果赋值给当前对象。

实现细节:

  • 如果移位量大于等于 BitSize,则将所有数据置为 0。
  • 计算字节移位和位移位的量 (byteShiftbitShift)。
  • 对于位移量为 0 的情况,使用 std::memmove 将字节右移,并填充移出的字节位置。
  • 对于非 0 位移量,逐字节处理右移,考虑到移出和移入的位。
  1. operator~() const

功能: 执行按位取反运算,并返回取反后的新 Number 对象。

实现细节:

  • 创建一个新的 Number 对象 result
  • 遍历所有字节,对每个字节执行按位取反 (~Data[i])。
  • 将取反后的结果存储到 result.Data[i] 中,并返回这个新对象。
  1. operator<<(size_t shift) const

功能: 执行按位左移运算,并返回一个新的 Number 对象。

实现细节:

  • 创建一个新的 Number 对象 result 作为当前对象的副本。
  • 调用 operator<<=result 进行左移操作,并返回 result
  1. operator>>(size_t shift) const

功能: 执行按位右移运算,并返回一个新的 Number 对象。

实现细节:

  • 创建一个新的 Number 对象 result 作为当前对象的副本。
  • 调用 operator>>=result 进行右移操作,并返回 result

实现运算符的大小比较

由于整数和小数他们的存储规律不同,所以我们不能在Number里面实现它,要不然代码太长了,我们使用虚函数,让子类实现它

virtual bool operator>=(const Number& other) const { return true; };
virtual bool operator<=(const Number& other) const { return true; };
virtual bool operator>(const Number& other) const { return true; };
virtual bool operator<(const Number& other) const { return true; };
virtual bool operator==(const Number& other) const { return true; };

接着我们可以实现compare函数进行比较他们

int Number::compare(const Number& other) const
{
    if (NumberType != other.NumberType)
    {
        throw std::invalid_argument("Cannot compare different types");
    }

    if (BitSize != other.BitSize)
    {
        throw std::invalid_argument("Bit sizes do not match");
    }

    if (*this >= other) // 使用大于等于运算符重载
    {
        if (*this == other) // 使用等于运算符重载
        {
            return 0; // 相等
        }
        return 1; // 当前对象大于 other
    }
    else
    {
        return -1; // 当前对象小于 other
    }
}

总结

通过运算符重载,我们可以使 Number 类的对象在进行数学运算时表现得像内置数据类型一样自然和直观。本文中,我们实现了以下运算符的重载:

加法 (+) 和减法 (-):

实现了 add 函数,允许两个 Number 对象进行加法或减法运算,并处理进位和借位。
加法和减法的实现通过逐字节运算来完成,适用于整数类型。
乘法 (*):

实现了 multiply 函数,使用逐位的移位和加法实现整数的乘法运算。
这种实现方法通过累加和移位操作来计算乘积。
除法 (/):

实现了 divide 函数,采用逐位的移位和减法实现整数的除法运算。
这种方法适用于整数除法,并通过迭代的减法操作计算商和余数。
这些运算符的重载不仅使 Number 类的操作更符合直观,还增强了其在数学计算中的灵活性。尽管当前实现主要适用于整数运算,进一步的改进可以扩展到支持浮点数和其他高级数学功能。通过运算符重载,我们可以更自然地处理复杂的数值运算,并为 Number 类提供强大的运算能力。

  • 31
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人才程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值