简体   繁体   English

为什么我们必须在 visual studio 2019 及更高版本中的复制构造函数和赋值运算符中使用 const

[英]Why we have to use const in copy constructor and assignment operator in visual studio 2019 and onwards versions

As you can see that operator+ is returning an object of class type MyString.如您所见,operator+ 返回 class 类型 MyString 的 object。

The assignment operator is not accepting this object in Visual Studio 2019 and giving an error of E0349 that no operands matches.赋值运算符在 Visual Studio 2019 中不接受此 object 并给出 E0349 错误,没有操作数匹配。 But, in Visual Studio 2012, it is running fine.但是,在 Visual Studio 2012 中,它运行良好。

Code:代码:

#include <iostream>
using namespace std;

class MyString {
private:
    char* str;
    int length;
public:
    MyString();
    MyString(const MyString&);
    bool operator!();
    friend ostream& operator<<(ostream&, MyString&);
    friend istream& operator>>(istream&, MyString&);
    MyString& operator=(const MyString&);
    MyString operator+(MyString&);
    MyString& operator-(MyString);
    MyString& operator ++ ();
    MyString& operator -- ();
    bool operator<(MyString&);
    char& operator[](int);
    char* operator()(int, int);
    void my_strcpy(char*&, char*);
    int my_strlen(char*);
};
MyString::MyString() {
    str = new char[1];
    str[0] = '\0';
    length = 0;
}
MyString::MyString(const MyString& obj) {
    int size = my_strlen(obj.str) + 1;
    str = new char[size];
    cout << "copy constructor called\n";
    my_strcpy(str, obj.str);
}
bool MyString::operator!() {
    if (str[0] == '\0')
        return true;
    return false;
}
ostream& operator<<(ostream& output, MyString& obj) {
    output << obj.str;
    return output;
}
istream& operator>>(istream& input, MyString& obj) {
    delete obj.str;
    obj.str = new char[50];
    input.getline(obj.str, 50);
    return input;
}
MyString& MyString::operator=(const MyString& obj) {
    if (this != &obj) {
        my_strcpy(str, obj.str);
    }
    return *this;
}
char& MyString::operator[](int index) {
    if (index >= 0 && index < my_strlen(str))
        return str[index];
    else {
        clog << "Index is out of range\n", exit(1);
    }
}
void MyString::my_strcpy(char*& destination, char* source) {
    int len_des = my_strlen(destination);
    int len_source = my_strlen(source);
    delete[]destination;
    destination = new char[len_source + 1];
    int index = 0;
    while (source[index] != '\0')
        destination[index] = source[index++];
    destination[index] = '\0';
}
MyString MyString::operator+(MyString& obj) {
    MyString newObj;
    int size = my_strlen(str) + my_strlen(obj.str) + 1;
    newObj.str = new char[size];
    char* temp = newObj.str;
    int index_str = 0;
    while (str[index_str] != '\0')
        *newObj.str++ = str[index_str++];
    index_str = 0;
    while (obj.str[index_str] != '\0')
        *newObj.str++ = obj.str[index_str++];
    *newObj.str = '\0';
    newObj.str = temp;
    cout << newObj.str << endl;
    return newObj;
}
MyString& MyString::operator ++ () {
    int size = my_strlen(str) + 2;
    char* new_str = new char[size];
    char* temp = new_str;
    int index = 0;
    while (str[index] != '\0')
        *new_str++ = str[index++];
    *new_str++ = 'a';
    *new_str = '\0';
    delete[]str;
    str = temp;
    return *this;
}
MyString& MyString::operator -- () {
    int size = my_strlen(str);
    char* new_str = new char[size];
    char* temp = new_str;
    int index = 0;
    while (index < size - 1)
        *new_str++ = str[index++];
    *new_str = '\0';
    delete[]str;
    str = temp;
    return *this;
}
MyString& MyString::operator-(MyString obj) {
    bool find = true;
    int obj_str_len = my_strlen(obj.str);
    int str_len = my_strlen(str);
    int start_ind = 0, end_ind = 0;
    if (str_len > obj_str_len) {
        for (int i = 0; str[i] != '\0'; i++) {
            if (str[i] == obj.str[0]) {
                start_ind = i;
                find = true;
                for (int j = i + 1, k = 1; obj.str[k] != '\0' && find; j++, k++) {
                    if (str[j] != obj.str[k]) {
                        find = false;
                    }
                    end_ind = j + 1;
                }
                if (find)
                    break;
            }
        }
        if (find) {
            while (str[end_ind] != '\0') {
                str[start_ind++] = str[end_ind++];
            }
            str[str_len - (end_ind - start_ind)] = '\0';
        }
    }
    return *this;
}
bool MyString::operator<(MyString& obj) {
    if (my_strlen(str) < my_strlen(obj.str))
        return true;
    else if (my_strlen(str) > my_strlen(obj.str))
        return false;
    for (int i = 0; str[i] != '\0'; i++) {
        if (str[i] < obj.str[i])
            return true;
        else if (str[i] > obj.str[i]) {
            return false;
        }
    }
    return false;
}
char* MyString::operator()(int starting_index, int ending_index) {
    int new_str_size = ending_index - starting_index + 2;
    char* new_str = new char[new_str_size];
    char* temp = new_str;
    int index = 0;
    int str_len = my_strlen(str);
    while (starting_index < str_len && index < 10)
        *new_str++ = str[starting_index++], index++;
    *new_str = '\0';
    return temp;
}
int MyString::my_strlen(char* str) {
    int size = 0;
    while (str[size] != '\0')
        size++;
    return size;
}

int main() {
    MyString str1, str2, str3, str4, str6;  

    if (!str1)
    {
        cout << "String 1 is Empty.\n";
        cout << "Str 1 = " << str1 << endl << endl << endl;
    }

    cout << "Enter String 1:\t";
    cin >> str1;


    cout << "Enter String 2:\t";
    cin >> str2;

    cout << "\n\n\nUser Entered:\n";
    cout << "String 1 = " << str1 << endl;
    cout << "String 2 = " << str2 << endl << endl << endl;

    cout << "Before str1 = str1; str1 = " << str1 << endl;
    str1 = str1;
    cout << "After str1 = str1, str1 = " << str1 << endl << endl << endl;

    cout << "Before str4 = str3 = str1+str2\n";
    cout << "str1 = " << str1 << endl;
    cout << "str2 = " << str2 << endl;
    cout << "str3 = " << str3 << endl;
    cout << "str4 = " << str4 << endl;

    str4 = str3 = str1 + str2;


    cout << "\n\n\nAfter str4 = str3 = str1+str2\n";
    cout << "str1 = " << str1 << endl;
    cout << "str2 = " << str2 << endl;
    cout << "str3 = " << str3 << endl;
    cout << "str4 = " << str4 << endl;

    cout << "\n\n\nEnter String 3:\t";
    cin >> str3;

    cout << "\n\n\nEnter String 4:\t";
    cin >> str4;

    cout << "\n\n\nstr3 = " << str3 << endl;
    cout << "str4 = " << str4 << endl;

    if (str3 < str4)
        cout << "String 3 is Less than String 4.\n";
    else
        cout << "String 3 is NOT Less than String 4.\n";
    MyString str5 = str1 + str2;;
    cout << "\n\n\nStr5:\t" << str5 << endl;
    cout << "Str5[7]:\t" << str5[7] << endl; 
    str5[7] = '$';

    cout << "\n\nStr5:\t" << str5 << endl;

    cout << "\n\n\nstr5(5, 10):\t" << str5(5, 10) << endl;

    cout << "\n\n ++Str3 :\t" << ++str3 << endl;

    str5 = str4 - str3;

    cout << "\n\n Str4 - Str3 :\t" << str5 << endl;

    cout << "\n\n --Str3 :\t" << --str3 << endl;

    cout << "\n\n --Str3 :\t" << --str3 << endl;

    str5 = str4 - str3;

    cout << "\n\n Str4 - str3 :\t" << str5 << endl;

    return 0;
}

Problem:问题:

The lines str3 = str1 + str2;str3 = str1 + str2; and MyString str4 = str1 + str2;MyString str4 = str1 + str2; will give an error that no operands matches.将给出没有操作数匹配的错误。 This error starts from Visual Studio 2019 and onwards versions.此错误从 Visual Studio 2019 及更高版本开始。

But, when I use const in both copy constructor and assignment operator (such as MyString(const MyString&); MyString& operator=(const MyString&); ), both lines ( str3 = str1 + str2; MyString str4 = str1 + str2; ) looks fine to compiler.但是,当我在复制构造函数和赋值运算符(例如MyString(const MyString&); MyString& operator=(const MyString&); )中都使用const时,两行( str3 = str1 + str2; MyString str4 = str1 + str2; )看起来对编译器很好。

But if I Write str3 = str1;但是如果我写str3 = str1; and MyString str4 = str2;MyString str4 = str2; now there is no need to write const in the copy constructor and assignment operator.现在不需要在拷贝构造函数和赋值运算符中写const了。

Why is the compiler showing this behaviour.?为什么编译器显示这种行为。?

The assignment operator that you have defined (ie, taking a non-const reference) requires that its argument be (or be convertible to ) an lvalue reference because it is non-const.您定义的赋值运算符(即采用非常量引用)要求其参数是(或可转换为左值引用,因为它是非常量。

However, the right-hand side of the assignment operator in the expression, str3 = str1 + str2 is the result of the addition, which is a temporary value and, as such, is a prvalue that cannot be (implicitly) converted to an lvalue.但是,表达式中赋值运算符的右侧str3 = str1 + str2是加法的结果,它是一个临时值,因此是不能(隐式)转换为左值的纯右值.

Adding the const qualifier to the parameter allows that operator to accept rvalue references (because you are explicitly stating that the referred-to value will not be modified).向参数添加const限定符允许该运算符接受右值引用(因为您明确声明不会修改引用的值)。

This is why, generally, copy constructors and copy assignment operators are defined with const &T parameters (though they don't have to be).这就是为什么通常使用const &T参数定义复制构造函数和复制赋值运算符(尽管它们不一定)。

For a fuller discussion of the differences between lvalues and rvalues, see here: Exact difference between rvalue and lvalue .有关左值和右值之间差异的更全面讨论,请参见此处:右值和左值之间的确切区别

On why/how this "binding of a temporary to an lvalue reference" was allowed in the earlier version(s) of Visual Studio, see: Non-const reference bound to temporary, Visual Studio bug?关于为什么/如何在 Visual Studio 的早期版本中允许这种“将临时值绑定到左值引用”,请参阅:非常量引用绑定到临时的 Visual Studio 错误? . .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM