C++: перегрузка строкового оператора

Могу ли я перегрузить существующую функцию/оператор в существующем классе?

Я пытался сделать:

#include <iostream>
#include <string>
using namespace std;

string& string::operator<<(const string& str) {
  this->append(str);
}

Но это дает мне ошибку:

test.cpp:5: error: too few template-parameter-lists

Как я могу это сделать? Или я не могу?


person texasbruce    schedule 17.07.2012    source источник
comment
Вы действительно пытаетесь вернуть string& (в отличие от чего-то вроде ostream&)? Вместо того, чтобы вводить синтаксис, я думаю, вам лучше просто делать то, что вы хотите, т.е. если у вас есть std::string с именем x и вы хотите добавить y, используйте для этого существующие механизмы в std::string (например, x += y) без добавления << перегрузка. Если, с другой стороны, это опечатка, и вы действительно хотите печатать в поток, обновите свой вопрос.   -  person Kevin Grant    schedule 17.07.2012
comment
@KevinGrant Ну, это не домашнее задание или рабочий вопрос. Это просто практика перегрузки операторов и классов.   -  person texasbruce    schedule 17.07.2012
comment
@KevinGrant И я думаю, что эти двое не противоречат друг другу? ostream#<< — это еще одна функция, отличная от string#<<, верно? И ‹‹ имеет ассоциативность слева направо, поэтому это не повлияет на cout.   -  person texasbruce    schedule 17.07.2012
comment
Да, operator<< на ostream& предназначено для изменения потока, а не строки; это отличается от того, что вы написали, но я подумал, может быть, вы действительно хотели это сделать. (Гораздо более типично перегружать << для работы с потоком.)   -  person Kevin Grant    schedule 17.07.2012


Ответы (3)


Вы не можете добавлять функции-члены в класс, пока не измените определение этого класса. Вместо этого используйте бесплатную функцию:

string& operator<<(string & lhs, const string & rhs) {
    return lhs += rhs;
}
person Benjamin Lindley    schedule 17.07.2012
comment
Значит, нет такой вещи, как повторный открытый класс? - person texasbruce; 17.07.2012
comment
@texasbruce: Нет, нет. Но с точки зрения пользователя это будет иметь ту же семантику, что и член. - person Benjamin Lindley; 17.07.2012
comment
@Benjamin: как компилятор разрешает перегрузку этого типа? как он различает функцию оператора-члена и функцию свободного оператора. - person Sach; 17.07.2012
comment
@Sachin: Члены объявляются в классе и имеют на один аргумент меньше, чем их аналоги со свободной функцией, поскольку вызывающий объект действует как первый аргумент. - person Benjamin Lindley; 17.07.2012
comment
@BenjaminLindley Но для других неоператорских функций вы можете использовать то же самое? Я попытался изменить оператор на некоторые литералы, и он сказал мне, что имя не является функцией-членом. Есть ли что-нибудь вокруг, чтобы сделать это, или мы просто не можем? - person texasbruce; 17.07.2012
comment
@texasbruce: нет, вы не можете добавлять функции-члены в класс. Какая выгода в этом? Кроме того, игнорируйте мой предыдущий комментарий о том, что он не работает должным образом, за исключением случаев, когда он помещен в пространство имен std, я думал о чем-то другом. - person Benjamin Lindley; 17.07.2012
comment
@BenjaminLindley Я все время работал с Ruby, и мне не нравятся некоторые функции-члены, представленные в стандартной библиотеке, поэтому я просто повторно открываю класс и делаю свою собственную реализацию. Итак, я предполагаю, что все классы запечатаны в С++? Если я хочу перегрузить/создать новую функцию-член, мне нужно создать новый класс и наследовать его? - person texasbruce; 17.07.2012
comment
@texasbruce: контейнеры стандартной библиотеки не предназначены для наследования, у них нет виртуальных деструкторов. Что плохого в том, чтобы просто писать бесплатные функции? Не все должны быть членами. - person Benjamin Lindley; 17.07.2012
comment
@BenjaminLindley У меня есть (ошибочное) представление о том, что для объектно-ориентированного языка функции/переменные/и т. д. всегда должен принадлежать объекту, а также свободная функция может вызвать конфликт имен. Может быть, мне следует создать пространство имен или класс для включения бесплатных функций? - person texasbruce; 17.07.2012
comment
@texasbruce: Да, это заблуждение. Функции, не являющиеся членами, улучшают инкапсуляцию. Кроме того, конфликты имен разрешаются (в дополнение к пространствам имен) типами аргументов. Если у вас есть две функции с одинаковыми именами, которые принимают одинаковые типы аргументов, то у вас конфликт, в противном случае все в порядке. И если кто-то может добавлять функции-члены в класс по своей прихоти, у вас будет точно такая же проблема (в отношении конфликтов имен) с функциями-членами, что и со свободными функциями. - person Benjamin Lindley; 17.07.2012

Я полагаюсь на ответ Бенджамина для создания потокового интерфейса для объекта string. Однако вместо этого вы можете использовать stringstream.

#include <sstream>

std::istringstream ss;
ss << anything_you_want;

std::string s = ss.str(); // get the resulting string
ss.str(std::string());    // clear the string buffer in the stringstream.

Это дает вам потоковый интерфейс, который вы хотите на string, без необходимости определять новую функцию.

Этот метод можно использовать в целом для расширения функциональности string. То есть определение класса-оболочки, который обеспечивает расширенную функциональность, а класс-оболочка также предоставляет доступ к базовому string.

person jxh    schedule 17.07.2012
comment
Извините, может быть, я должен сделать это более ясным. Мой главный вопрос заключается в том, как перегрузить функцию-член, которая уже существует в существующем классе, но не в том, как использовать строку... - person texasbruce; 17.07.2012
comment
@texasbruce: В вашем конкретном примере вы хотели добавить новый оператор, поскольку string не определяет для себя метод оператора <<. Тем не менее, я обновил ответ, чтобы объяснить мотивацию. С уважением - person jxh; 17.07.2012

Использовать

std::острингстрим

#include <sstream>
#include <iostream>

using namespace std;

int main()
{
    std::ostringstream ss;
    ss << "Hello" << " " << "world";

    std::string s = ss.str(); 
    ss.str(std::string()); 

    cout << s << endl;
    return 0;
}

https://onlinegdb.com/rkanzeniI

person Bandula Dharmadasa    schedule 27.05.2020