当我重载动态字符串类的运算符时没有匹配的构造函数

No matching constructor when I overload operator for dynamic string class

本文关键字:构造函数 运算符 动态 重载 字符串      更新时间:2023-10-16

我的字符串类有问题。

构造

函数和复制构造函数:

private:
    char * buf;
public:
    String( const char * s = "")
    {
        buf = strdup(s);
    }
    String( String &s)
    : buf(strdup(s.buf))
    {
    }

操作员:

String operator + ( const String &s )
{
    char* tmp = new char[strlen(buf) + strlen(s.buf) + 1]; // +1 for the terminating ''
    strcpy(tmp,buf);
    strcat(tmp,s.buf);
    String result;
    delete[] result.buf;
    result.buf = tmp;
    return result;
}
String operator += ( const String s )
{
    delete_char_array(buf);
    char* tmp = new char[strlen(buf) + strlen(s.buf) + 1];
    strcpy(tmp,buf);
    strcat(tmp,s.buf);
    buf = strdup(tmp);
    delete_char_array(tmp);
    return *this;
}
void print( ostream & out )
{
    char *p = buf;
    out << p;
}

我已经实现了<<运算符

ostream & operator << ( ostream & out,  String str )
{
    str.print(out);
    return out;
}

我的 main(( 函数是:

int main()
{
    String firstString("First");
    String secondString("Second");
    cout << firstString + secondString << endl;
    (firstString+=secondString).print(cout);
}

我可以通过 String.print(cout( 正确获取输出,但 g++ 会告诉我

cout << firstString + secondString << endl;` does not have the matching
constructor for `String::String(String)`

有两种选择,1. String::String( char * c)和 2. String::String(String &s) .

这应该是复制构造函数签名:

String(String const& s)

因此,引用可以绑定到 operator+ 返回的 R 值。此外,您还应该将此签名用于operator<<

ostream &operator<<(ostream &out, String const& str)

这些片段中的任何一个都可以修复错误,但是 (1( 是至关重要的做法(如您所见(,(2( 避免复制。

你还需要做void print(ostream &out) const,因为你想用String const&来称呼它,即使operator+也应该const。请不要忘记const...

您不修改引用 - 使其成为对常量的引用。成员函数不会修改*this - 使其const。就是这么简单。

你在这里也忘记了一个&String operator+=(const String s).

我们还没有完成,正如PaulMcKenzie的评论所指出的那样,还有很多事情需要解决。

你的String类有一些问题。

首先,strdup 的使用返回应使用 free() 解除分配的已分配缓冲区。 但是,在重载的+=+函数中,您使用的是new []delete []。 您正在使用C++,因此请假装 strdup(( 不存在

尽管您试图小心它,但像这样混合分配函数是未定义的行为。 相反,请在整个类代码中使用new []delete []

其次,复制构造函数签名应为:

    String(const String &s);

所以你的构造函数现在应该看起来像这样:

private:
    char * buf;
public:
    String( const char* s = "") : buf(new char[strlen(s) + 1]())
    {
        strcpy(buf, s);
    }
    String(const String &s) : buf(new char[strlen(s.buf) + 1]())
    {
        strcpy(buf, s.buf);
    }

现在需要添加析构函数(如果尚未添加

(:
String::~String() { delete [] buf; }

接下来是你的operator +=operator +. operator +=应该返回对当前对象的引用,而不是全新的对象。

String& operator += ( const String& s )
{
    char* tmp = new char[strlen(buf) + strlen(s.buf) + 1];
    strcpy(tmp,buf);
    strcat(tmp,s.buf);
    delete [] buf;
    buf = tmp;
    return *this;
}

请注意,返回类型是对 String 的引用。 另请注意,在尝试删除旧缓冲区之前,首先分配串联字符串的内存。 需要这样做以确保缓冲区在引发异常时不会operator new失效。

鉴于此,operator +可以这样写:

String operator + ( const String& s )
{
    String tmp(*this);
    return tmp += s;
}

我们使用operator +=作为辅助函数。 所做的只是创建一个与*this相同的临时String。 然后我们只需返回传入的String operator +=的结果。 简短而简单。

您缺少的最后一件事是赋值运算符。如果没有赋值运算符,则无法安全地执行以下操作:

String s1("abc");
String s2;
s2 = s1; // <-- assignment operator here

实现赋值运算符非常容易,前提是您有一个复制构造函数和工作析构函数。 请转到此链接了解如何实现此功能:

复制/交换成语。