簡體   English   中英

為什么我們必須在 visual studio 2019 及更高版本中的復制構造函數和賦值運算符中使用 const

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

如您所見,operator+ 返回 class 類型 MyString 的 object。

賦值運算符在 Visual Studio 2019 中不接受此 object 並給出 E0349 錯誤,沒有操作數匹配。 但是,在 Visual Studio 2012 中,它運行良好。

代碼:

#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;
}

問題:

str3 = str1 + str2; MyString str4 = str1 + str2; 將給出沒有操作數匹配的錯誤。 此錯誤從 Visual Studio 2019 及更高版本開始。

但是,當我在復制構造函數和賦值運算符(例如MyString(const MyString&); MyString& operator=(const MyString&); )中都使用const時,兩行( str3 = str1 + str2; MyString str4 = str1 + str2; )看起來對編譯器很好。

但是如果我寫str3 = str1; MyString str4 = str2; 現在不需要在拷貝構造函數和賦值運算符中寫const了。

為什么編譯器顯示這種行為。?

您定義的賦值運算符(即采用非常量引用)要求其參數是(或可轉換為左值引用,因為它是非常量。

但是,表達式中賦值運算符的右側str3 = str1 + str2是加法的結果,它是一個臨時值,因此是不能(隱式)轉換為左值的純右值.

向參數添加const限定符允許該運算符接受右值引用(因為您明確聲明不會修改引用的值)。

這就是為什么通常使用const &T參數定義復制構造函數和復制賦值運算符(盡管它們不一定)。

有關左值和右值之間差異的更全面討論,請參見此處:右值和左值之間的確切區別

關於為什么/如何在 Visual Studio 的早期版本中允許這種“將臨時值綁定到左值引用”,請參閱:非常量引用綁定到臨時的 Visual Studio 錯誤? .

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM