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

BigInt C++ and proper copy constructor?

本文关键字:复制 构造函数 C++ BigInt      更新时间:2023-10-16

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

-BigIntVector是一个自定义向量类。与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;
}

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

这是我之前的一篇文章,解决了您对C++中使用new的误解。该描述中对C#的引用同样适用于Java:在标准C++中垃圾收集是自动的吗?

关于评论中的一个问题:"正式成员的语法是什么"。暗示这一点的评论只是说不要将元素声明为指针(只需省略*)。总之,对于此类:

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

在这种情况下,问题出在BigIntVector类中。由于这是一个分配内存和管理指针的程序,因此它需要一个复制构造函数。如果这是一项家庭作业,我建议将三条规则应用于BigIntVector的实施。您将需要以下所有

  • 复制构造函数,用于复制内存
  • 赋值运算符,它还复制内存
  • 析构函数,用于释放内存

如果不是家庭作业,我建议用std::vector代替BigIntVector


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

如果你必须有一个这样的任务,正确的形式应该是这样的:

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;
}

好吧。我不知道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; }

这里的主要原则是零法则。你设计你的类,使默认生成的函数做正确的事情:复制构造函数,移动构造函数,移动赋值,复制赋值,析构函数。

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

内置类型都遵循规则,我假设BigIntVector遵循0.3或5的规则。(如果没有,修复它,这样它就可以了!)

我做的其他更改是:

  • 将非可变运算符作为非成员函数是一种很好的风格。如果您发现自己能够将const放在成员运算符上,那么它应该是非成员是一个好兆头。有关此主题的更多信息,请参阅本线程
  • 注释应该说明代码所说的内容之外的其他内容。在析构函数上加上注释"析构函数",或在二进制+运算符上加上"二进制+运算符",都会毫无理由地扰乱屏幕

long构造函数中,int tempNum = num;应该是long tempNum = num;;并且应该初始化skip