文章目录
前言
在 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
类实现的,允许对类实例进行位操作,包括按位与、按位或、按位异或、按位取反、左移和右移。以下是每个运算符的详细实现和说明:
operator&=(const Number& other)
功能: 执行按位与运算,并将结果赋值给当前对象。
实现细节:
- 首先检查
BitSize
是否匹配,以确保两个Number
对象的位数相同。 - 遍历所有字节,逐个进行按位与运算 (
Data[i] &= other.Data[i]
)。 - 操作完成后,将结果存储回
Data
中。
operator|=(const Number& other)
功能: 执行按位或运算,并将结果赋值给当前对象。
实现细节:
- 首先检查
BitSize
是否匹配。 - 遍历所有字节,逐个进行按位或运算 (
Data[i] |= other.Data[i]
)。 - 将结果存储回
Data
中。
operator^=(const Number& other)
功能: 执行按位异或运算,并将结果赋值给当前对象。
实现细节:
- 检查
BitSize
是否匹配。 - 遍历所有字节,逐个进行按位异或运算 (
Data[i] ^= other.Data[i]
)。 - 将结果存储回
Data
中。
operator<<=(size_t shift)
功能: 执行按位左移运算,并将结果赋值给当前对象。
实现细节:
- 如果移位量大于等于
BitSize
,则将所有数据置为 0。 - 计算字节移位和位移位的量 (
byteShift
和bitShift
)。 - 对于位移量为 0 的情况,使用
std::memmove
将字节左移,并填充移出的字节位置。 - 对于非 0 位移量,逐字节处理左移,考虑到移出和移入的位。
operator>>=(size_t shift)
功能: 执行按位右移运算,并将结果赋值给当前对象。
实现细节:
- 如果移位量大于等于
BitSize
,则将所有数据置为 0。 - 计算字节移位和位移位的量 (
byteShift
和bitShift
)。 - 对于位移量为 0 的情况,使用
std::memmove
将字节右移,并填充移出的字节位置。 - 对于非 0 位移量,逐字节处理右移,考虑到移出和移入的位。
operator~() const
功能: 执行按位取反运算,并返回取反后的新 Number
对象。
实现细节:
- 创建一个新的
Number
对象result
。 - 遍历所有字节,对每个字节执行按位取反 (
~Data[i]
)。 - 将取反后的结果存储到
result.Data[i]
中,并返回这个新对象。
operator<<(size_t shift) const
功能: 执行按位左移运算,并返回一个新的 Number
对象。
实现细节:
- 创建一个新的
Number
对象result
作为当前对象的副本。 - 调用
operator<<=
对result
进行左移操作,并返回result
。
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 类提供强大的运算能力。