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
关键字
这样的话,问题出在你的BigIntVector
class。因为那是分配内存和管理指针的那一个,所以那是需要复制构造函数的那一个。如果这是家庭作业,我建议将 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;
}
我正在尝试为 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
关键字
这样的话,问题出在你的BigIntVector
class。因为那是分配内存和管理指针的那一个,所以那是需要复制构造函数的那一个。如果这是家庭作业,我建议将 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;
}