C++ 运算符重载的基本规则和习惯用法是什么?

C++ 运算符重载的基本规则和习惯用法是什么?,c++,operators,operator-overloading,c++-faq,C++,Operators,Operator Overloading,C++ Faq,注意:答案是按特定顺序给出的,但由于许多用户根据投票而不是给出的时间对答案进行排序,因此以下是答案的索引,以最有意义的顺序排列: 赋值运算符 输入和输出运算符 函数调用运算符 比较运算符 算术运算符 数组下标 类指针类型的运算符 (注意:这是一个条目。如果您想对在此表单中提供常见问题解答的想法提出批评,则可以在此处进行评论。该问题的答案将在中进行监控,其中常见问题解答的想法首先从中开始,因此您的答案很可能会被提出此想法的人阅读。) C++中运算符重载的三个基本规则 在C++中运

注意:答案是按特定顺序给出的,但由于许多用户根据投票而不是给出的时间对答案进行排序,因此以下是答案的索引,以最有意义的顺序排列:

  • 赋值运算符
  • 输入和输出运算符
  • 函数调用运算符
  • 比较运算符
  • 算术运算符
  • 数组下标
  • 类指针类型的运算符
(注意:这是一个条目。如果您想对在此表单中提供常见问题解答的想法提出批评,则可以在此处进行评论。该问题的答案将在中进行监控,其中常见问题解答的想法首先从中开始,因此您的答案很可能会被提出此想法的人阅读。)

C++中运算符重载的三个基本规则 <>在C++中运算符重载时,有< >强> >三个基本规则。与所有这些规则一样,确实存在例外情况。有时人们会偏离这些准则,结果也不错,但这种积极的偏离很少。至少,在我所看到的100个这样的偏差中,有99个是没有道理的。然而,这也可能是千分之999。所以你最好遵守以下规则

  • 如果运算符的含义不明显且不存在争议,则不应重载该运算符。相反,请提供一个具有精心选择的名称的函数。
    基本上,重载操作符的首要规则的核心是:不要这样做。这可能看起来很奇怪,因为关于运算符重载还有很多需要了解的地方,所以很多文章、书籍章节和其他文本都涉及到了这一切。但是,尽管这似乎是显而易见的证据,但只有少数情况下操作符重载是合适的。原因是,实际上很难理解运算符应用程序背后的语义,除非在应用程序域中使用运算符是众所周知且无可争议的。与普遍的看法相反,情况几乎从未如此

  • 始终坚持运算符的众所周知的语义。
    C++对过载操作符的语义没有限制。编译器将乐于接受实现二进制
    +
    运算符以从其右操作数中减去的代码。然而,这种运算符的用户决不会怀疑表达式
    a+b
    b
    中减去
    a
    。当然,这假定应用程序域中运算符的语义是无可争议的

  • 始终提供所有相关操作。
    操作员之间以及与其他操作相关。如果您的类型支持
    a+b
    ,则用户也可以调用
    a+=b
    。如果它支持前缀增量
    ++a
    ,那么他们希望
    a++
    也能工作。如果他们能够检查
    a
    ,他们肯定也希望能够检查
    a>b
    。如果他们可以复制您的类型,他们希望赋值也能起作用


  • 继续.< /P> C++中运算符重载的三个基本规则 <>在C++中运算符重载时,有< >强> >三个基本规则。与所有这些规则一样,确实存在例外情况。有时人们会偏离这些准则,结果也不错,但这种积极的偏离很少。至少,在我所看到的100个这样的偏差中,有99个是没有道理的。然而,这也可能是千分之999。所以你最好遵守以下规则

  • 如果运算符的含义不明显且不存在争议,则不应重载该运算符。相反,请提供一个具有精心选择的名称的函数。
    基本上,重载操作符的首要规则的核心是:不要这样做。这可能看起来很奇怪,因为关于运算符重载还有很多需要了解的地方,所以很多文章、书籍章节和其他文本都涉及到了这一切。但是,尽管这似乎是显而易见的证据,但只有少数情况下操作符重载是合适的。原因是,实际上很难理解运算符应用程序背后的语义,除非在应用程序域中使用运算符是众所周知且无可争议的。与普遍的看法相反,情况几乎从未如此

  • 始终坚持运算符的众所周知的语义。
    C++对过载操作符的语义没有限制。编译器将乐于接受实现二进制
    +
    运算符以从其右操作数中减去的代码。然而,这种运算符的用户决不会怀疑表达式
    a+b
    b
    中减去
    a
    。当然,这假定应用程序域中运算符的语义是无可争议的

  • 始终提供所有相关操作。
    操作员之间以及与其他操作相关。如果您的类型支持
    a+b
    ,则用户也可以调用
    a+=b
    。如果它支持前缀增量
    ++a
    ,那么他们希望
    a++
    也能工作。如果他们能够检查
    a
    ,他们肯定也希望能够检查
    a>b
    。如果他们可以复制您的类型,他们希望赋值也能起作用


  • 继续。

    运算符重载的一般语法
    X& X::operator=(X rhs)
    {
      swap(rhs);
      return *this;
    }
    
    std::ostream& operator<<(std::ostream& os, const T& obj)
    {
      // write obj to stream
    
      return os;
    }
    
    std::istream& operator>>(std::istream& is, T& obj)
    {
      // read obj from stream
    
      if( /* no valid object of T found in stream */ )
        is.setstate(std::ios::failbit);
    
      return is;
    }
    
    class foo {
    public:
        // Overloaded call operator
        int operator()(const std::string& y) {
            // ...
        }
    };
    
    foo f;
    int a = f("hello");
    
    inline bool operator==(const X& lhs, const X& rhs){ /* do actual comparison */ }
    inline bool operator!=(const X& lhs, const X& rhs){return !operator==(lhs,rhs);}
    inline bool operator< (const X& lhs, const X& rhs){ /* do actual comparison */ }
    inline bool operator> (const X& lhs, const X& rhs){return  operator< (rhs,lhs);}
    inline bool operator<=(const X& lhs, const X& rhs){return !operator> (lhs,rhs);}
    inline bool operator>=(const X& lhs, const X& rhs){return !operator< (lhs,rhs);}
    
    bool operator<(const X& rhs) const { /* do actual comparison with *this */ }
    
    class X {
      X& operator++()
      {
        // do actual increment
        return *this;
      }
      X operator++(int)
      {
        X tmp(*this);
        operator++();
        return tmp;
      }
    };
    
    class X {
      X& operator+=(const X& rhs)
      {
        // actual addition of rhs to *this
        return *this;
      }
    };
    inline X operator+(X lhs, const X& rhs)
    {
      lhs += rhs;
      return lhs;
    }
    
    class X {
            value_type& operator[](index_type idx);
      const value_type& operator[](index_type idx) const;
      // ...
    };
    
    class X {
      value_type& operator[](index_type idx);
      value_type  operator[](index_type idx) const;
      // ...
    };
    
    class my_ptr {
            value_type& operator*();
      const value_type& operator*() const;
            value_type* operator->();
      const value_type* operator->() const;
    };
    
    enum Month {Jan, Feb, ..., Nov, Dec}
    
    void* operator new(std::size_t) throw(std::bad_alloc); 
    void  operator delete(void*) throw(); 
    void* operator new[](std::size_t) throw(std::bad_alloc); 
    void  operator delete[](void*) throw(); 
    
    class X { /* ... */ };
    char buffer[ sizeof(X) ];
    void f()
    { 
      X* p = new(buffer) X(/*...*/);
      // ... 
      p->~X(); // call destructor 
    } 
    
    void* operator new(std::size_t,void* p) throw(std::bad_alloc); 
    void  operator delete(void* p,void*) throw(); 
    void* operator new[](std::size_t,void* p) throw(std::bad_alloc); 
    void  operator delete[](void* p,void*) throw(); 
    
    class my_class { 
      public: 
        // ... 
        void* operator new();
        void  operator delete(void*,std::size_t);
        void* operator new[](size_t);
        void  operator delete[](void*,std::size_t);
        // ... 
    }; 
    
    class my_string {
    public:
      operator const char*() const {return data_;} // This is the conversion operator
    private:
      const char* data_;
    };
    
    void f(const char*);
    
    my_string str;
    f(str); // same as f( str.operator const char*() )
    
    void f(my_string&);
    void f(const char*);
    
    f(my_string());
    
    class my_string {
    public:
      explicit operator const char*() const {return data_;}
    private:
      const char* data_;
    };
    
    prog.cpp: In function ‘int main()’: prog.cpp:15:18: error: no matching function for call to ‘f(my_string)’ prog.cpp:15:18: note: candidates are: prog.cpp:11:10: note: void f(my_string&) prog.cpp:11:10: note: no known conversion for argument 1 from ‘my_string’ to ‘my_string&’ prog.cpp:12:10: note: void f(const char*) prog.cpp:12:10: note: no known conversion for argument 1 from ‘my_string’ to ‘const char*’
    struct Foo
    {
       int a;
       double b;
    
       std::ostream& operator<<(std::ostream& out) const
       {
          return out << a << " " << b;
       }
    };
    
    Foo f = {10, 20.0};
    std::cout << f;
    
    Foo f = {10, 20.0};
    f << std::cout
    
    struct Foo
    {
       int a;
       double b;
    };
    
    std::ostream& operator<<(std::ostream& out, Foo const& f)
    {
       return out << f.a << " " << f.b;
    }
    
    Foo f = {10, 20.0};
    std::cout << f;