BigInt C++ 和正确的复制构造函数?

BigInt C++ and proper copy constructor?

我正在尝试为 C++ 实现 BigInt,但 运行 遇到了复制构造函数的问题。你可以看到我注释掉了复制构造函数的原始代码,它只是 *this = orig;。但我发现你需要使用指针来代替它。然而,我不完全确定这是如何工作的,目前代码没有正确地制作复制构造函数。

-BigIntVector 是自定义向量 class。与 STL 矢量比较。

BigInt.h:

class BigInt {
private:
    BigIntVector bigIntVector;
    bool isPositive;
    int base;
    unsigned int skip;

    BigIntVector* ptr; //pointer to copy?

public:
    // copy constructor
    BigInt(BigInt const& orig);

    // constructor where data value is passed as a long
    BigInt(long num);

    // destructor
    ~BigInt();

    // binary '+' operator
    BigInt operator+(BigInt const& other) const;

    // unary '+' operator
    BigInt operator+() const;

    //more operator unloading functions

这是我目前在 BigInt.cpp 中构造函数的实现:

// copy constructor
BigInt::BigInt(BigInt const& orig) {
    ptr = new BigIntVector;
    *ptr = *orig.ptr;
    //*this = orig;
}

// constructor where operand is a long
BigInt::BigInt(long num) {
    //this->data = num;

    ptr = new BigIntVector;

    base = 10;

    int sizeOfLong = 0; //holds size of num
    int tempNum = num; 

    //get size of num
    if (tempNum == 0) {
        sizeOfLong = 1;
    }
    while (tempNum != 0)
    {
        tempNum /= 10;
        ++sizeOfLong;
    }

    //resize vector to match size of long
    bigIntVector = BigIntVector(sizeOfLong);

    if (num < 0) {
        isPositive = false;
        num *= -1;
    }
    else {
        isPositive = true;
    }
    long pushedNum;
    //cout << "num: " << num << endl;
    for (int i = sizeOfLong - 1; i >= 0; --i) {
        pushedNum = (long)(num%base);
        bigIntVector.setElementAt(i, pushedNum);
        num /= base;
    }
}

// destructor
BigInt::~BigInt() {
    //delete *this;
}

//code for overloading operators for BigInt below

BigIntVector 构造函数的代码:

BigIntVector::BigIntVector(long initialSize)
{
    vectorTotalSize = initialSize;
    vectorIncrementSize = initialSize;

    vectorArray = (long *)malloc(initialSize*sizeof(long));
    for (long i = 0; i < initialSize; i++) vectorArray[i] = 0;

    nextValue = 0;
}

嗯。我不知道 BigIntVector* ptr; //pointer to copy? 是什么,所以我认为这是一个错误。您的代码应如下所示:

class BigInt
{
private:
    BigIntVector bigIntVector;
    bool isPositive;
    int base;
    unsigned int skip;

public:
    // constructor where data value is passed as a long
    BigInt(long num = 0);

    BigInt &operator+=(BigInt const& other);

    // Other accessors...
};

inline BigInt operator+(BigInt a, BigInt const &b) { a += b; return a; }

这里的主要原则是Rule of Zero。您设计 class 以便默认生成的函数正确执行以下操作:复制构造函数、移动构造函数、移动赋值、复制赋值、析构函数。

那么您的 class 定义仍然很简单。为了实现这个目标,所有数据成员都必须正确地实现这些功能——要么自己遵循零规则,要么实际拥有这些功能。

内置类型都遵循规则,我假设 BigIntVector 遵循 0,3 或 5 的规则。(如果不是,请修复它!)

我所做的其他更改是:

  • 非变异运算符是非成员函数是一种很好的风格。如果您发现自己能够将 const 放在成员运算符上,这是一个好兆头,表明它应该是非成员。有关此主题的更多信息,请参阅 this thread
  • 注释应该对代码的内容进行补充说明。在析构函数上添加注释 "destructor",或者在二进制 + 运算符上添加 "binary + operator" 只会无缘无故地弄乱你的屏幕。

在你的long构造函数中,int tempNum = num;应该是long tempNum = num;;你应该初始化 skip.

在现实世界中(作业之外),BigInt class 不需要显式复制构造函数。内存分配应该委托给一个单独的 class——最有可能是 std::vector。如果你需要一个指针作为 class 成员(在这种情况下不太可能),使用 std::shared_ptr 管理它就不需要复制构造函数。

这是我之前的一篇 post,它解决了您对在 C++ 中使用 new 的误解。该描述中对 C# 的引用同样适用于 Java:Is garbage collection automatic in standard C++?

关于评论中的一个问题:"what is the syntax for full members"。建议的评论只是说不要将元素声明为指针(只需省略 *)。总结一下,对于这个 class:

  • 你不需要指针
  • 你不需要拷贝构造函数
  • 您不需要使用 new 关键字

这样的话,问题出在你的BigIntVectorclass。因为那是分配内存和管理指针的那一个,所以那是需要复制构造函数的那一个。如果这是家庭作业,我建议将 rule of three 应用于 BigIntVector 的实现。您将需要 全部 项:

  • 拷贝构造函数,拷贝内存
  • 一个赋值运算符,它也复制内存
  • 析构函数,释放内存

如果不是作业,我建议把BigIntVector换成std::vector


为非平凡的 class 声明一个复制构造函数是个坏主意,因为您通常需要显式复制每个成员(或者它们将被默认初始化而不是复制)——更好让编译器为您完成以避免错误。

如果你必须为这个作业准备一份,正确的形式应该是这样的:

BigInt::BigInt(BigInt const& orig)
 : bigIntVector(orig.bigIntVector)
 , isPositive(orig.isPositive)
 , base(orig.base)
 , skip(orig.skip)
{
// empty body
}

将算术运算符转发到复合赋值运算符的规范形式是以下的一些变体:

T& T::operator += ( T const & b )
{
  ...class-specific math logic that modifies the object...
  return (*this);
}

T operator + ( T const & a, T const & b )
{
  T temp(a); // create a temporary copy of 'a' rather than modifying it
  return temp += b;
}