为什么这个构造函数是按原样编写的?

时间:2013-03-13 20:15:57

标签: c++ object copy-constructor default-constructor c-strings

我们的教授在网上发布了一个自定义的'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;
};

3 个答案:

答案 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分配。