[英]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.