Оператор перегрузки и модификация строки

Я узнаю о перегрузке операторов. Я создал простой класс, чтобы проверить это.

class Beer{
public:
Beer(int oner , int twor , string name){
this -> one = oner;
this -> two = twor;
this -> name = name;
};
int getOne(){

return this -> one;
};
int getTwo(){

return this -> two;
};
string getName(){
return this -> name;
};
Beer operator + (const Beer &a)const {

return Beer(5,two+a.two,"firstName");

};
Beer operator + (string a)const {

this -> name =  this -> name +" "+a;

};

private:

int one;
int two;
string name;
};

Я пытаюсь выяснить, как преобразовать строку с перегруженным операндом. Моя функция, которую я объявил

Beer operator + (string a)const {
this -> name =  this -> name +" "+a;
};

Выдает ошибку о передаче константной строки.

Я пытался с помощью

Beer operator + ( const string *a)const {
swap(this -> name , this -> name + " " + a);
return *this;
};

Который жаловался на то, что одна строка — самая простая, а вторая — основная строка.

Идея проста.

Beer one ( 5, 6, "one")
one + "two"
// one.name = "one two"

Как правильно это сделать?

// ошибка со свопом

error: no matching function for call to 'swap(const string&, std::basic_string<char>)'|

// ошибка со строкой

passing 'const string {aka const std::basic_string<char>}' as 'this' argument of 'std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(std::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' discards qualifiers [-fpermissive]|

0

Решение

Комментарии:

  1. Не включайте весь std Пространство имен. Вы, вероятно, столкнетесь с неприятными конфликтами имен с вашим собственным кодом. Самое большее, используйте символы, которые вам нужны явно, например, using std::string;,

  2. Если вам не нужна копия значения для изменения, передавайте большие объекты, такие как std::string по постоянной ссылке. Когда вы объявляете параметр как имеющий тип значения std::stringвы получаете копию строки, и это дорого, если вам не нужна копия для изменения внутри вашей функции.

    Это давняя проблема со стандартом C ++: подобная деталь реализации, которая не должна иметь отношения к пользователю функции, просачивается в интерфейс (объявление функции). Тем не менее, когда копия имеет смысл, пусть компилятор даст вам ее, не набирая столько текста. Таким образом:

    // prefer this
    std::string fooize(std::string foo) {
    assert(foo.size() > 0);
    foo.insert(1, "foo");
    return foo;
    }
    // over this
    std::string fooize(const std::string & bar) {
    assert(bar.size() > 0);
    auto foo = bar;
    foo.insert(1, "foo");
    return foo;
    }
    
  3. Используйте список инициализаторов, тогда вам не нужно будет заниматься глупой гимнастикой (у вас было oner, twor имена:

    Beer(int one, int two, const std::string & name) :
    one(one),
    two(two),
    name(name)
    {}
    
  4. Объявите методы доступа только для чтения const:

    int getOne() const { return one; }
    
  5. Возвращать большие значения, такие как строки, по константной ссылке; пользовательский код, скорее всего, поможет компилятору сделать копию при необходимости автоматически:

    const std::string & getName() const { return name; }
    
    // use:
    Beer beer{0,0,""};
    std::cout << (beer.getName() + "!") << std::endl; // makes a copy of name as needed
    
  6. в + оператор, принимающий строку, вы должны вернуть новый объект, а не изменять this, Вы в значительной степени должны делать это так, как это делал другой оператор +.

    Beer operator +(const std::string & a) const {
    return Beer(one, two, name + " " + a);
    };
    
  7. Если вы хотите изменить свой объект, вы хотите operator +=:

    Beer & operator+=(const std::string & a) {
    name += " ";
    name += a;
    return *this;
    }
    
  8. Даже если ваш класс был разработан для экспериментов с операторами, вы всегда должны учитывать, облегчают ли операторы жизнь или нет. Например, ваш класс состоит из трех человек. Сразу не ясно, над каким из этих членов будут прооперированы, если иное не будет ясно из семантики класса. Было бы намного понятнее иметь имена методов addToOne, addToTwo, а также appendToNameНапример, вместо оператора (ов), или просто позволяя пользователю установить член через сеттеры, как setOne(int one) { this->one = one; }, Пользователь тогда просто сделает beer.setOne(beer.getOne() + 2);,

  9. Подумайте о присвоении имен получателям без get префикс, например,

    class Beer {
    int m_one;
    public int one() const { reeturn m_one; }
    };
    

    Это меньше печатать для пользователя. Стандартная библиотека, а также большие библиотеки, такие как boost а также Qt следовать этой конвенции, например, у тебя есть std::string::size()не std::string::getSize(), так далее.

2

Другие решения

Beer operator + (string a)const {
this -> name =  this -> name +" "+a;
};

Вы не должны изменять содержимое объекта, для которого вызывается оператор +; в конце концов, если вы выполняете A = B + C, содержимое B не должно меняться. Компилятор правильно информирует вас об этом, потому что это константная функция.

Скорее создайте временный объект для хранения «суммы» и верните ее.

Beer operator + (string a)const {
return Beer(one, two, name + " " + a);
};
1

В вашем operator+() Вот:

Beer operator+( string a ) const
{
this->name = this->name + " " + a;
};

const подпись функции является гарантией для компилятора, что при вызове функции вы не измените данные в объекте, но измените данные в объекте.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector