Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 运算符重载的基本规则和习惯用法是什么?_C++_Operators_Operator Overloading_C++ Faq - Fatal编程技术网

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
    。如果他们可以复制您的类型,他们希望赋值也能起作用


  • 继续>

    C++中运算符重载的一般语法

    不能更改C++中内置类型的运算符的含义,运算符只能为用户定义类型1重载。也就是说,至少一个操作数必须是用户定义的类型。与其他重载函数一样,对于某一组参数,运算符只能重载一次

    <>并非所有操作符都可以在C++中重载。在不能重载的操作符中有:<代码> ./COD> <代码>::<代码> > sieOS/<代码>代码> Type ID >代码> >代码> *>代码> C++中的唯一三元运算符,<代码>:<代码> < /P> <>在C++中可以重载的操作符是:

    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;
    }
    
    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(); 
    
    • 算术运算符:
      +/code>
      -
      *
      /
      %
      +=
      -=
      *=
      %=
      (所有二进制中缀)<代码>+
      -
      (一元前缀)<代码>++
      --
      (一元前缀和后缀)
    • 位操作:
      &
      ^
      &=
      ^=
      =
      (所有二进制中缀)<代码>~
      (一元前缀)
    • 布尔代数:
      =
      =
      =
      | |
      &&
      (所有二进制中缀)<代码>(一元前缀)
    • 内存管理:
      new
      new[]
      delete
      delete[]
    • 隐式转换运算符
    • 杂项:
      =
      []
      ->
      ->*
      (所有二进制中缀)<代码>*
      &
      (所有一元前缀)
      ()
      (函数调用,n元中缀)
    然而,事实上,你可以超载所有这些并不意味着你应该这样做。请参阅运算符重载的基本规则

    在C++中,运算符以<>强>函数的形式重载,名称为<强>。与其他函数一样,重载运算符通常可以实现为其左操作数类型的成员函数,也可以实现为非成员函数。您是否可以自由选择或绑定使用其中一个取决于几个条件。2应用于对象x的一元运算符
    @
    3可以作为
    operator@(x)
    x.operator@()
    调用。应用于对象
    x
    y
    的二进制中缀运算符
    @
    ,称为
    运算符(x,y)
    
    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;