C++ 作业 - 使用动态数组重载 >> 运算符

Posted

技术标签:

【中文标题】C++ 作业 - 使用动态数组重载 >> 运算符【英文标题】:C++ Homework - overloading >> operator with dynamic array 【发布时间】:2021-02-27 03:26:02 【问题描述】:

简介:

我有一个家庭作业,要为“大于现有类型可以存储的整数”创建一个类型。 我们应该将数字存储在一个数字数组中(向后以便于数学逻辑)。 我正在使用动态数组将信息存储在对象中。 我至少需要重载 +、-、*、、> 运算符。 .cpp 和 .h 文件也必须分开。

问题:

不太清楚如何根据类属性和所需的操作重载 >> 运算符。

BigIntegers.h
#include <string>
#include <iostream>

typedef int* BigIntPtr;

class BigIntegers 
private:
    int size; // based on string size, if neg string size -1
    BigIntPtr number; // dynamic array ptr
    bool isNeg; // set default to false, assumes a positive number
public:
    explicit BigIntegers(std::string num = "");
    BigIntegers(const BigIntegers &bi);
    ~BigIntegers();

    friend std::istream &operator>>(std::istream &is, BigIntegers &bi) 
        /**
         * using eg "is >> bi.data;" doesn't seem viable given the data manipulation needed
         * see constructor
         */
        std::string input;
        getline(is,input);
        bi = BigIntegers(input);
        return is;
    

    friend std::ostream &operator<<(std::ostream &os, const BigIntegers &bi) 
        if(bi.isNeg) //add sign if needed
            os << '-';
        for(int s=bi.size-1;s>-1;s--) //print reverse
        
            os << bi.number[s];
        
        return os;
    
;
BigIntegers.cpp
#include <algorithm>
#include "BigIntegers.h"

BigIntegers::BigIntegers(std::string num) 
    //if null
    if(num.empty())
    
        size = 0;
        number = NULL;
        isNeg = 0;
        return;
    

    //determine if its negative
    if (num.find('-') == 0)
    
        num.erase(remove(num.begin(),num.end(), '-'),num.end());
        isNeg =true;
    else isNeg= false;
    size = num.length();
    number = new int[size];
    //add array backwards for math optimization
    std::string rev; rev.assign(num.rbegin(),num.rend());
    for(int i = 0; i < size; i++)
    
        number[i]=rev[i]-'0';
    


BigIntegers::~BigIntegers() 
    delete [] number;
    size =0;
    isNeg =0;

#include <iostream>
#include "BigIntegers.h"

using std::cout;
using std::cin;
using std::string;

int main() 
    //basic functionality test
    string stringInt = "123456";
    string stringIntNeg = "-99987654321";

    BigIntegers test1(stringInt);
    cout << test1 << "\n";
    BigIntegers test2(stringIntNeg);
    cout << test2 << "\n";

    //iostream test
    cout << "Enter a big integer in the form 123456 or -123456.\n";
    BigIntegers test3;
    cin >> test3;
    cout << test3 << "\n";

    return 0;

output
pr4_bigIntegers\cmake-build-debug\pr4_bigIntegers.exe
123456
-12345678987654321
Enter a big integer in the form 123456 or -123456.
5789256
-57883070081-2144186072

Process finished with exit code 0

注意:

此外,有时输出几乎是正确的,但包含负数或其他一些垃圾值。例如) cin >> 5314 , cout

edit - 我意识到在 4 位数之后引入了垃圾。实验仍在继续。

分配说明 - (对于其他上下文,这是直接复制/粘贴)

C++ 中现有的整数类型不能存储非常大的整数。我们需要一种新类型来存储我们在处理科学问题时可能需要的这些大整数。 您可以通过将整数存储为数字数组来表示整数。

设计并实现一个整数运算类,其中一个数字被实现为一个数字数组。数组的每个条目都是从 0 到 9(含)的数字。 表示的数字是数组中数字的串联。

您至少需要为此类重载 +、-、*、、> 运算符。尝试重载除法运算符 /。

不要忘记实现三组:赋值运算符、复制构造函数和析构函数。

除法运算符是整数运算符,因此它返回商的整数部分。您需要了解此类的目的是存储大整数,因此在重载这些运算符的过程中,您不应将数组表示形式转换为常规整数表示形式。同样,我们假设这些整数不能通过使用内置整数类型来处理,因此您的显式构造函数应该有一个字符串类型参数,而不是整数类型参数,并从字符串中获取每个字符,将其转换为数字并存储它到你的阵列。为了轻松执行操作,您可能希望在数组中以相反的顺序存储一个整数。

使用动态数组存储整数。 包括代码的专业文档和适当的缩进 将头文件与实现文件分开 测试课堂的各个方面。

来自老师的电子邮件说明

只需回答你们中的几个问题。

    整数是有符号的,因为当你做减法时,你可能会得到一个负整数。所以使用数组的第一个点来存储 0 或 1(0 表示负数,1 表示正数)。

    说明不允许您将字符串参数转换为整数。我的意思是您不应该将字符串 s="123456" 转换为 int n=123456。但是,您必须将字符 1 转换为整数 1,...,字符 6 转换为整数 6 并将每个字符存储到您的数组中。

【问题讨论】:

将其作为字符串输入,一次解析一个字符。 ***.com/help/minimal-reproducible-example。在这里提出问题时,使用固定输入而不是在运行时读取输入是个好主意。您的 test2 输出与输入不匹配。这是一个错误还是 operator 一个问题是,如果你在输入中没有找到负号,你永远不会设置isNeg 前 2 个测试是固定的,每次对我来说都可以正常工作。第三个测试检查分配所需的 >> 运算符的重载。 但是你的问题是什么。负号是由于在构造函数中未将 isNeg 设置为 false 造成的。您的 >> 运算符是正确的。 【参考方案1】:

您的重载 >> 运算符似乎是正确的。 你的第二个问题:减号不是垃圾。

bool isNeg; // 设置默认为 false,假设为正数

您从未将其设置为 false。我调试了你的代码,解决方法很简单:

BigIntegers::BigIntegers(std::string num) : isNeg(false) 
    //your constructor stuff

我建议改用unsigned short 类型的动态数组。 将每个数字保存在一个整数中,每个整数的范围从 -21.4 亿到 21.4 亿不等,这将需要大量内存。您不需要存储负值。您可以考虑使用字符,因为您可以将每个整数数字转换为 char 和向后但需要更少的内存。最节省内存的方式可能是从 0 到 9 的 Enum。

您的类需要存储大于 long long(8 个字节)的数字,至少 64 个字节(number array)+ 4 个字节(size 变量)+ 1 个位(isNeg)。这对于一个数字来说是相当大的:)

根据您的任务,不允许使用整数。所以你必须改变它:) 我的方法利用了枚举类的每个元素都可以根据其在枚举类定义中的索引转换为整数类型的事实(反之亦然)。最终,每个整数都可以转换为字符。因此,仍然存在整数,但您很难发现它们。

enum class DigitZero,One,Two,Three,Four,Five,Six,Seven,Eight,Nine;

typedef Digit* BigIntPtr;

class BigIntegers 

public:
    explicit BigIntegers(std::string num = "");
    BigIntegers(const BigIntegers& src);
    BigIntegers& operator=(const BigIntegers&src);
    ~BigIntegers();

    friend bool operator<(const BigIntegers& lhs, const BigIntegers& rhs);
    friend bool operator>(const BigIntegers& lhs, const BigIntegers& rhs);
    friend BigIntegers operator+(const BigIntegers& lhs, const BigIntegers& rhs);
    friend BigIntegers operator-(const BigIntegers& lhs, const BigIntegers&rhs);

    friend std::istream &operator>>(std::istream &is, BigIntegers &bi);
    friend std::ostream &operator<<(std::ostream &os, const BigIntegers &bi);
private:
    size_t size; // based on string size, if neg string size -1
    BigIntPtr number; // dynamic array ptr
    bool isNeg; // set default to false, assumes a positive number
;

您的 .cpp 文件:

#include <algorithm>
#include "bigint.h"

using namespace std;

BigIntegers::BigIntegers(std::string num):isNeg(false)

    //if null
    if (num.empty())
    
        size = 0;
        number = NULL;
        isNeg = 0;
        return;
    


    //determine if its negative
    if (num.find('-') == 0)
    
        num.erase(remove(num.begin(), num.end(), '-'), num.end());
        isNeg = true;
    
    size = num.length();
    number = new Digit[size];

    //add array backwards for math optimization
    std::string rev; rev.assign(num.rbegin(), num.rend());
    Digit * aux = number;
    std::for_each (rev.begin(),rev.end(),[&](const char c)
    
        *number = Digit(c - '0');
        number++;
    );

    number = aux;


BigIntegers::BigIntegers(const BigIntegers & src)
    : size(src.size), numbernew Digit[src.size], isNeg(src.isNeg)

    for (auto i = number, j = src.number; i < number + size; i++, j++)
    
        *i = *j;
    


BigIntegers & BigIntegers::operator=(const BigIntegers & src)

    if (this == &src)
        return *this;

    size = src.size;
    isNeg = src.isNeg;

    if (number != NULL) delete[] number;
    number = new Digit[src.size];
    for (auto i = number, j = src.number; i < number + size; i++,j++)
    
        *i = *j;
    

    return *this;


BigIntegers::~BigIntegers()

    delete[] number;



bool operator<(const BigIntegers & lhs, const BigIntegers & rhs)

    if (lhs.size > rhs.size) return false;
    if (lhs.size < rhs.size) return true;

    for (auto i = lhs.number + lhs.size - 1, j = rhs.number + rhs.size - 1; i >= lhs.number || j >= rhs.number; i--, j--)
    
        if (char(*i) > char(*j))return false;
        if (char(*i) < char(*j))return true;
    

    return false;


bool operator>(const BigIntegers & lhs, const BigIntegers & rhs)

    return !(lhs < rhs);


BigIntegers operator+(const BigIntegers & lhs, const BigIntegers & rhs)

    string value = "";
    Digit aux = Digit::Zero;
    for (auto i = lhs.number, j = rhs.number; i < lhs.number + lhs.size || j < rhs.number + rhs.size; i++, j++)
    
        char c = char(aux);
        c += i < lhs.number + lhs.size ? char(*i) : char(0);
        c += j < rhs.number + rhs.size ? char(*j) : char(0);
        aux = Digit(0);
        if (c > 9)
        
            aux = Digit::One;
            c -= 10;
        
        // 48 is '0' in Ascii table
        value += (c+48);
    

    if (aux == Digit::One)
    
        value += '1';
    

    reverse(value.begin(), value.end());

    return BigIntegers(value);


BigIntegers operator-(const BigIntegers & lhs, const BigIntegers & rhs)

    bool reverse = false;
    if (lhs < rhs)reverse = true;
    const BigIntegers& bigger = reverse ? rhs : lhs;
    const BigIntegers& smaller = reverse ? lhs : rhs;

    Digit aux = Digit::Zero;
    std::string value = "";
    for (auto i = bigger.number, j = smaller.number; i < bigger.number+bigger.size; i++, j++)   
    
        char c1 = char(*i);
        char c2 = j < smaller.number+smaller.size ? char(*j) : 0;
        c2 += char(aux);
        aux = Digit::Zero;
        if (c1 < c2)
        
            aux = Digit::One;
            c1 = c1 + 10 - c2;
        
        else
        
            c1 -= c2;
        

        if (c1 > 0 || i < bigger.number + bigger.size - 1)
        
            // if condition is to avoid leading zeros
            value += (c1 + 48);
        
    

    if (reverse)value += "-";
    std::reverse(value.begin(), value.end());

    return BigIntegers(value);


istream& operator>>(istream& is, BigIntegers& bi)

    std::string input;
    getline(is, input);
    bi = BigIntegers(input);
    return is;


std::ostream &operator<<(std::ostream &os, const BigIntegers &bi) 
    if (bi.isNeg) //add sign if needed
        os << '-';
    for (int s = bi.size - 1; s > -1; s--) //print reverse
    
        os << static_cast<int>(bi.number[s]);
    
    return os;

您可能会注意到,我使用整数替换了所有 for 循环;) 至少我没有使用一次int 关键字。但是,+10 这样的东西当然是一个 const 整数。

到目前为止,我还不能确定反向存储数字是否有利。

乘法由你决定。不错的任务:)

【讨论】:

使用动态数组来存储你的整数。 好的,这就是原因。但是,您不必在此数组中使用整数。考虑改用 unsigned short 或 char。 我不确定我是否不能在数组中使用整数,请注意教授的英语是第二语言,翻译时经常会丢失东西。我需要发邮件去查。不过,根本不使用任何整数会很尴尬,因为我需要对其他重载进行数学运算。 好的。我已根据我的建议更新了答案。 > 运算符有点懒惰 - 不是 100% 正确的。考虑到两个相同的值,运算符将返回 true,即 lhs 大于 rhs。但是,在这种情况下,它应该返回 false。【参考方案2】:

这个重载解决了垃圾值的问题。

BigIntegers &BigIntegers::operator=(const BigIntegers &bi) 
    //if number is already assigned here
    if(this==&bi) 
        return *this;
    //else assign the number
    size = bi.size; isNeg = bi.isNeg;
    if (number != nullptr) delete[] number;
    number= new int[bi.size];
    for (auto i = number, j = bi.number; i < number+size; i++, j++)
        *i = *j;
    return *this;

【讨论】:

以上是关于C++ 作业 - 使用动态数组重载 >> 运算符的主要内容,如果未能解决你的问题,请参考以下文章

c++学习笔记:多态

扩大动态数组(不允许vector<>,类分配)

在 C++ 中使用动态内存分配创建二维数组

C++ 运算符重载

C++ 运算符重载四(自定义数组类)

模板化动态数组中的运算符重载 []