【问题标题】:Overloading operator and modifiyng string重载运算符和修改字符串
【发布时间】:2016-04-01 19:15:25
【问题描述】:

我正在学习运算符重载。我创建了一个简单的类来测试它。

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

在传递 const 字符串时抛出错误。

我尝试过使用

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]|

【问题讨论】:

  • 请发布您得到的确切编译器错误。
  • 顺便说一句,类方法定义末尾的分号是不用的。

标签: c++ operator-overloading


【解决方案1】:

评论:

  1. 不要包含整个 std 命名空间。您可能会与您自己的代码发生令人讨厌的名称冲突。最多,使用你需要明确的符号,例如using std::string;.

  2. 除非您需要修改值的副本,否则请通过 const 引用传递像 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. 使用初始化列表,你就不需要做愚蠢的名字体操(你有onertwor 名字:

    Beer(int one, int two, const std::string & name) :
      one(one),
      two(two),
      name(name)
    {}
    
  4. 声明只读访问器 const:

    int getOne() const { return one; }
    
  5. 通过 const 引用返回大值,如字符串;用户代码可能会让编译器在需要时自动生成副本:

    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. 即使您的课程旨在试验运算符,您也应该始终考虑运算符是否让生活更轻松。例如,您的班级有三个成员。除非从类的语义中可以清楚地看出这些成员中的哪一个会被操作,否则这并不是很明显。例如,使用名为addToOneaddToTwoappendToName 的方法而不是运算符,或者简单地让用户通过设置器设置成员,例如setOne(int one) { this-&gt;one = one; },这样会更清楚。然后用户只需执行beer.setOne(beer.getOne() + 2);

  9. 考虑在没有get 前缀的情况下命名getter,例如

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

    为用户减少打字。标准库以及像 boostQt 这样的大型库都遵循这个约定,例如你有std::string::size(),而不是std::string::getSize(),等等。

【讨论】:

  • 这里面+和+=有什么区别?如果我想修改当前对象,为什么要使用 +=?
  • @user3706129 因为这是惯例
  • @user3706129 因为operator + 预计会创建一个临时值,而operator += 预计会修改现有值。这就是这些运算符在所有其他正常类型上的行为方式,包括内置(例如int)和标准(例如std::string)。例如。你可以写1 + 2,否则它是无效的,因为+ 会尝试修改一个右值。你不能写1 += 2,因为1 不是左值,这是+= 需要的。
  • @user3706129 当然,没有人会阻止你让任何操作员做任何事情,但这会让你的类的使用变得相当混乱。约定的存在是有原因的:它们让生活更轻松。
【解决方案2】:
Beer operator + (string a)const {
  this -> name =  this -> name +" "+a;
};

你不应该改变被调用+运算符的对象的内容,毕竟如果你执行A = B + C,B的内容不应该改变。编译器会正确通知您这一点,因为它是一个 const 函数。

而是创建一个临时对象来保存“总和”并返回它。

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

【讨论】:

    【解决方案3】:

    在您的operator+() 此处:

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

    函数签名上的const向编译器保证,当函数被调用时,您不会更改对象中的数据,但您会更改对象中的数据。

    【讨论】:

    • 我刚刚注意到我把 const 留在那里,但没有它会引发 seg 错误。
    • 不要去掉const,是正确的,看我的回答。
    猜你喜欢
    • 1970-01-01
    • 2015-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-04
    相关资源
    最近更新 更多