我们的教授在网上发布了一个自定义的'String'模板文件,并在不久前问我们填写下面的功能。我的问题是,为了尝试理解这一点,为什么前三个构造函数具有Text = NULL;
及其下方,this = source;
,以及其他形式。我觉得每个人都应该说Text = the_input_parameter
。
非常感谢,这是代码:
class String
{
public:
// Default constructor
String()
{
Text = NULL;
}
String(const String& source)
{
Text = NULL;
// Call the assignment operator to perform deep copy
*this = source;
}
String(const char* text)
{
Text = NULL;
// Call the assignment operator to perform deep copy
*this = text;
}
~String()
{
delete[] Text;
}
// Assignment operator to perform deep copy
String& operator = (const char* text)
{
// Ddispose of old Text
delete[] Text;
// +1 accounts for NULL-terminator
int trueLength = GetLength(text) + 1;
// Dynamically allocate characters on heap
Text = new char[trueLength];
// Copy all characters from source to Text; +1 accounts for NULL-terminator
for ( int i = 0; i < trueLength; i++ )
Text[i] = text[i];
return *this;
}
// Returns a reference to a single character from this String
char& operator [] (int index) const
{
int length = GetLength();
// Check for valid index
if ( (index < 0) || (index > length) )
{
stringstream error;
error << "operator[] - index " << index << " is out of bounds (0.." << (length - 1) << ")";
throw String(error.str().c_str());
}
return Text[index];
}
private:
// The encapsulated C-string
char* Text;
};
答案 0 :(得分:6)
为什么你不应该在赋值方面实现构造函数:
所以,为什么在你的示例代码中以这种方式完成的答案可能是你的教授不太了解C ++编程。
否则,很难说:完全没有任何意义。
然而,另一方面,即在复制构造方面实施复制分配是非常常见的,被称为复制和交换习语。
这很简单,例外安全且通常有效,并且如下所示:
class Foo
{
public:
void swap_with( Foo& other ) throw()
{
// No-throwing swap here.
}
void operator=( Foo other )
{
other.swap_with( *this );
}
};
是的,就是这样。
变体包括仅为swap
命名交换器,并让赋值运算符返回引用,有些人更喜欢通过引用传递参数,然后复制(使用复制构造)。
答案 1 :(得分:1)
这只是将公共代码分解为辅助函数的一种方法。在这种情况下,operator=()
充当辅助函数。它的功能是释放当前字符串(在本例中为NULL
)并执行右侧的深层复制。
我觉得每个人都应该说
Text = the_input_parameter
。
对于String(const String& source)
,由于source
不是正确的类型,因此无法编译。
对于String(const char* text)
,这不正确,因为那只是指定指针而不是执行深层复制。
以上假设您只向我们展示了类的一部分,并且实际的类定义了适当的赋值运算符和析构函数。如果没有,你需要一位新教授。
答案 2 :(得分:0)
该类管理内存,因此析构函数释放它,赋值运算符为新数据分配new并释放旧数据(应该按顺序)。
然后初始赋值的解释是明确的:你需要将成员字段初始化为正确的值,否则它将包含垃圾(某些指针指向某处),哪些代码将尝试使用和释放。
虽然从代码中看不到,但也可能会为const String&
和类型转换运算符operator const char *() const
分配。