在类 C++ 中使用运算符+= 连接 2 个字符串

Concatenate 2 string using operator+= in class C++

提问人:Hector Ta 提问时间:6/5/2022 最后编辑:Hector Ta 更新时间:6/6/2022 访问量:445

问:

在问之前,我见过一些类似的问题,但我仍然停留在使用 .operator+=

目前,我可以通过构造函数方法正确获取单独的字符串。但是当我编译代码时,方法中的行显示错误:str[length+i] = s[i];String& String::operator+= (const String& s)

'operator[]' 不匹配(操作数类型为 'const String' 和 'unsigned int')

所以我需要你的帮助来修复这个错误。

这是我的代码:

#include <iostream>
#include <cstring>
 
class String {
 
    // Initialise char array
    char* data;
    unsigned length;
 
public:
    // Constructor without arguments 
    String();
 
    // Constructor with 1 arguments
    String(char* s);
 
    // Copy Constructor
    String(const String& source);
 
    // Move Constructor
    String(String&& source);
 
    // Destructor
    ~String() { delete[] data; }
    
    /*! 
     *  @brief String length.
     *  @return Value in String @c length.
     */
    unsigned len ( ) const;
    
    /*! 
     *  @brief Append to String.
     *  @param[in] s A String object.
     *  @return A String reference to *this.
     *  @post String will equal the concatenation of itself with @a s.
     */
    String& operator+= (const String& s);
};
 
// Constructor with no arguments
String::String()
    : data{ nullptr }
{
    data = new char[1];
    data[0] = '\0';
}
 
// Constructor with one arguments
String::String(char* s)
{
    if (s == nullptr) {
        data = new char[1];
        data[0] = '\0';
    }
 
    else {
 
        data = new char[strlen(s) + 1];
 
        // Copy character of s[]
        // using strcpy
        strcpy(data, s);
        data[strlen(s)] = '\0';
 
        std::cout << data << "\n";
    }
}
 
// Copy Constructor
String::String(const String& source)
{
    data = new char[strlen(source.data) + 1];
    strcpy(data, source.data);
    data[strlen(source.data)] = '\0';
}
 
// Move Constructor
String::String(String&& source)
{
    data = source.data;
    source.data = nullptr;
}

unsigned String::len ( ) const 
{
    return length;
}

String& String::operator+= (const String& s) 
{
    unsigned len = length + s.len();
    char*    str = new char[len];

    for (unsigned j=0; j < length; j++)
        str[j] = data[j];

    for (unsigned i=0; i < s.len(); i++)
        str[length+i] = s[i];

    delete data;
    length = len;
    data   = str;
    return *this;    
}
 
int main()
{
    // Constructor with no arguments
    String a;
 
    // Convert string literal to
    // char array
    char temp[] = "Hello world.";
 
    // Constructor with one argument
    std::cout << "s1: ";
    String s1{ temp };
 
    // Copy constructor
    String s11{ a };
 
    char temp1[] = "Goodbye!";
    std::cout << "s2: ";
    String s2{ temp1 };
    
    String s3 = String s1 + String s2;

    return 0;
}

主函数的另一种写法:

int main()
{
String s1("Hello World.");
String s2("Goodbye!");
std::cout << "s1: " << s1 << std::endl;
std::cout << "s2: " << s2 << std::endl;
String s3 = s1 + s2;
std::cout << "s3: " << s3 << std::endl;
std::cout << "The last char of s3: " << s3[s3.size()-1] << std::endl;
return 0;
}

预期结果:

s1: Hello World.
s2: Goodbye!
s3: Hello World.Goodbye!
The last char of s3: !

如何修改我的代码以正确获取和最后一个字符?s3s3

C++ OOP 重载 赋值运算符

评论

1赞 Homer512 6/5/2022
您尝试调用 String 对象,但 String 类没有定义此类运算符。定义运算符或将行更改为operator[]str[length+i] = s.data[i]
0赞 Adrian Mole 6/5/2022
构造函数不会设置成员的值。length
0赞 fabian 6/5/2022
除非您将构造函数更改为 此外,否则编译器实际上不应允许工作 此外,您应该遵守 5 规则:由于您正在定义复制和移动构造函数,因此您还应该定义复制和移动赋值运算符。String s1("Hello World.");String(const char*)
0赞 Ted Lyngmo 6/6/2022
你现在已经改变了问题,所以我的答案看起来很奇怪。请不要在得到答案后对您的问题进行此类更改。
0赞 Hector Ta 6/6/2022
@TedLyngmo 对不起。我已改回原来的代码。请添加 s3[s3.size() -1] 的示例代码。谢谢。

答:

1赞 Vlad from Moscow 6/5/2022 #1

对于初学者来说,两个构造函数都没有设置数据成员。 所以运营商length

String& String::operator+= (const String& s) 
{
    unsigned len = length + s.len();
    char*    str = new char[len];
    //...

具有未定义的行为。

另外,如果数据成员长度已初始化,则需要将

    char*    str = new char[len + 1];

而不是

    char*    str = new char[len];

为终止零字符“\0”保留内存,因为您在复制构造函数中使用了标准的 C 字符串函数strcpy

strcpy(data, source.data);

并且该类没有用于 loo[ 的下标运算符

for (unsigned i=0; i < s.len(); i++)
    str[length+i] = s[i];

而且你忘了附加终止零字符.'\0'

请注意,此表达式中使用的类中没有成员函数size

s3[s3.size()-1]

而这个结构

String s3 = String s1 + String s2;

无效。至少你应该写

字符串 s3 = s1 + s2;

并相应地定义运算符 +。

评论

0赞 Hector Ta 6/6/2022
当我在创建方法 int size() { return _size; } 后运行 s3[s3.size()-1] 时,它显示错误:'operator[]'(操作数类型为“String”和“int”)不匹配。如何解决?请在原始帖子中检查我修改后的代码
2赞 Ted Lyngmo 6/5/2022 #2

在许多构造函数中,您没有设置 which 使其具有不确定的值 - 读取此类值会使程序具有未定义的行为。因此,首先要解决以下问题:length

#include <algorithm> // std::copy_n

// Constructor with no arguments
String::String() : data{new char[1]{'\0'}}, length{0} {}

// Constructor with one argument
String::String(const char* s) {     // note: const char*
    if (s == nullptr) {
        data = new char[1]{'\0'};
        length = 0;
    } else {
        length = std::strlen(s);
        data = new char[length + 1];
        std::copy_n(s, length + 1, data);
    }
}

// Copy Constructor
String::String(const String& source) : data{new char[source.length + 1]},
                                       length{source.length}
{
    std::copy_n(source.data, length + 1, data);
}

// Move Constructor
String::String(String&& source) : String() {
    std::swap(data, source.data);
    std::swap(length, source.length);
}

在您尝试使用下标运算符时,,但您没有添加这样的运算符,因此使用 :operator+=String::operator[]s[i]s.data[i]

String& String::operator+=(const String& s) {
    unsigned len = length + s.length;
    char* str = new char[len + 1];
    for (unsigned j = 0; j < length; j++) str[j] = data[j];
    for (unsigned i = 0; i < s.length; i++) str[length + i] = s.data[i];
    str[len] = '\0';
    delete[] data;        // note: delete[] - not delete
    length = len;
    data = str;
    return *this;
}

如果您希望能够在对象上使用下标运算符,则需要添加一对成员函数:String

class String {
public:
    char& operator[](size_t idx);
    char operator[](size_t idx) const;
};
char& String::operator[](size_t idx) { return data[idx]; }
char String::operator[](size_t idx) const { return data[idx]; }

为了工作,你需要一个免费的重载:String s3 = s1 + s2;operator+

String operator+(const String& lhs, const String& rhs) {
    String rv(lhs);
    rv += rhs;
    return rv;
}

此外,为了支持打印您在替代功能中尝试的类似内容,您需要一个重载。例:Stringmainoperator<<

class String {
    friend std::ostream& operator<<(std::ostream& os, const String& s) {
        os.write(s.data, s.length);
        return os;
    }
};

完整演示

评论

0赞 Hector Ta 6/6/2022
我可以得到 s3 = s1 + s2,但在我创建了方法 int size() { return _size; } 后无法得到 s3[s3.size()-1] 。我怎样才能得到它?
0赞 Ted Lyngmo 6/6/2022
@HectorTa 正如我所提到的,您需要添加。我在答案中添加了一个示例。String::operator[]
0赞 Hector Ta 6/6/2022
我只能通过添加 std::cout <<数据<<“\n”来获得 s3;在 operator+= 方法中。如何在 operator+ 中获取它?此外,添加 2 运算符 [] 后,我仍然无法获得 s3[s3.size()-1] 的值;它没有像以前那样的编译错误,但对 [] 显示为空。
0赞 Ted Lyngmo 6/6/2022
@HectorTa我不确定我是否理解,但我添加了另一个您似乎缺少的功能()和一个指向演示程序的链接,您可以在其中看到我在工作中的所有建议。operator<<