class String
{
char* array;
public:
String(const char* s)
{
array = new char[strlen(s) + 1]{ '\0' };
strcpy(array, s);
}
~String()
{
if (array)
{
delete[]array;
}
}
String operator+ (const char* p) //返回对象
{
String temp(p);
char* tempStr = temp.array;
temp.array = new char[strlen(array) + strlen(tempStr) + 1]{ '\0' };
strcpy(temp.array, array);
strcat(temp.array, p);
delete[]tempStr;
return temp;
}
friend ostream& operator<<(ostream& output, String& x); // <<函数重载只能定义成友元
};
ostream& operator << (ostream& output, String& x) //对<<重载的方式
{
output << x.array;
return output;
}
int main()
{
String string1("mystring");
cout << string1 + "ab" << endl;
cout << string1 << endl;
return 0;
}
Я впервые задаю вопрос здесь, поэтому, пожалуйста, простите меня, если есть какие-то плохие описания :)
Возвращаясь к делу, я перегрузил операторы + и <<, поэтому я хочу получить вывод «mystringab» с помощью cout<<string1+"ab"<<endl, но вывод искажен.
Я думаю, что может быть проблема с перегруженной функцией оператора +, может кто-нибудь, пожалуйста, скажите мне, в чем проблема?
И если я хочу получить правильный результат, как мне переписать перегруженную функцию?
Спасибо, но я только что попробовал, и он все еще выводит искаженные символы :(
Смотрите мой ответ ниже и этот рабочая демонстрация. Также не забудьте убедиться, что в вашей программе нет неопределенного поведения.
Большое спасибо за ваш ответ :) Я изучаю объектно-ориентированное программирование, поэтому я не очень понимаю некоторые механизмы.
позже посмотрю внимательнее
delete[]tempStr; прямо перед тем, как return temp; освободит буфер принадлежит по темп. Это фатально.
String не соблюдает правило трех или друзья. Это означает, что его нельзя безопасно скопировать. Передача или возврат по значению приведет к созданию копий. String operator+ (const char* p) возвращается по значению, делает копию и, таким образом, будет фатальным.
Приятного чтения: Каковы основные правила и идиомы перегрузки операторов?
как мне переписать перегруженную функцию по значению
Тактическое примечание: если вы добавите учетную переменную для отслеживания длины строки, вы сможете сэкономить на вызовах strlen снова и снова.
Вам нужно возвращать значение из operator+, это означает, что вы должны сделать String копируемым (или переписать, чтобы гарантировать исключение, но копируемый класс гораздо полезнее, чем тот, который не удастся скопировать). Прочтите размещенную ссылку о Правило трех.
Я предлагаю задать второй вопрос, который конкретно касается улучшения operator+, потому что Stack Overflow лучше всего работает, когда решает одну проблему на каждый вопрос. Однако в опубликованной ссылке Каковы основные правила и идиомы перегрузки операторов? есть очень важные предложения, которые могут устранить необходимость в этом вопросе.
Я думал об этом несколько часов и, наконец, понял, где ошибся. Когда temp возвращается, конструктор копирования, написанный самим компилятором, вызывается для создания shallow copy, тем самым создавая анонимный объект, char *array этого анонимного объекта и temp.array указывают на один и тот же адрес, поэтому, когда функция завершается и temp уничтожается , char *array анонимного объекта также удаляется, поэтому будут выводиться искаженные символы. Решение состоит в том, чтобы самостоятельно определить конструктор копирования, чтобы сделать глубокую копию.





Проблема в том, что второй параметр перегруженного operator<< не может быть привязан к String rvalue, поскольку вторым параметром является lvalue ссылка на неконстантный String.
how should I rewrite the overloaded function?
Вам нужно сделать второй параметр перегруженным operator<< a const String&, чтобы он мог работать и со вторым аргументом "ab", как показано ниже:
//---------------------------------------- vvvvv------------>low-level const added here
friend ostream& operator<<(ostream& output,const String& x);
Точно так же сделайте то же самое в определении:
//----------------------------------- vvvvv------------>low-level const added here
ostream& operator << (ostream& output,const String& x)
{
output << x.array;
return output;
}
Кроме того, убедитесь, что ваша программа не имеет неопределенного поведения. Например, убедитесь, что вы используете delete или delete[] только тогда, когда это безопасно (те данные, на которые указывает указатель, больше не нужны). Вы можете использовать такие инструменты, как valgrind, для обнаружения некоторых основных проблем.
Сделайте второй параметр
operator<<aconst String&.