操作符(运算符)重载注意事项(含模板类中<<;;重载)

Posted 松狮MVP

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了操作符(运算符)重载注意事项(含模板类中<<;;重载)相关的知识,希望对你有一定的参考价值。

一、用 友元全局函数 或者  成员函数  重载运算符
      关键区别是:成员函数有this指针,友元函数没有成员指针,传递参数的方式不同,实现代码不同。

      对于:objectL  op  objectR
      成员函数重载 解释为: objectL.operator op (objectR)  ===》objectL通过this指针传递,objectR由参数objectR传递;
      友元函数重载 解释为: operator op(objectL,objectR) ===》左右操作数都是通过参数传递;


二、注意事项:

1)友元函数和成员函数选择方法:

           当无法修改左操作数的类时,使用全局函数进行重载;
           =, [], ()和->操作符  只能 通过 成员函数  进行重载( ()是函数调用符 );
               运算符 [] 和 () 是二元运算符,[] 和 () 只能用成员函数重载,不能用友元函数重载 ;

2)用 友元函数 重载 <<、 >>操作符
          istream 和 ostream 是 C++ 的预定义流类;
          cin 是 istream 的对象,cout 是 ostream 的对象;
          运算符 << 由ostream 重载为插入操作,用于输出基本类型数据;
          运算符 >> 由 istream 重载为提取操作,用于输入基本类型数据;
          用友员函数重载 << 和 >> ,输出和输入用户自定义的数据类型;

    a)用全局函数方法实现 << 操作符
          ostream& operator<<(ostream &out, Complex &c1)
         
              //out<<"12345,生活真是苦"<<endl;
              out<<c1.a<<" + "<<c1.b<<"i "<<endl;
              return out;

         


          //调用方法

          cout<<c1;


          //链式编程支持,//函数返回值充当左值 需要返回一个引用
          cout<<c1<<"abcc";
          //cout.operator<<(c1).operator<<("abcd");
          
    b)类成员函数方法无法实现 << 操作符重载
          //因拿到cout这个类的源码  ,  //cout.operator<<(c1);


三、operator= 必须重载为成员函数
     重载函数原型为:
        类型 &  类名 :: operator= ( const  类名 & ) ;

     步骤:
        1 先释放旧的内存;
        2 按照参数分配新内存;
        3 =操作符 从右向左,最后返回一个自身(*this);


四、为什么不要重载&&和||操作符?

     1)&& 和 || 是C++中非常特殊的操作符;

     2)&& 和 || 内置实现了短路规则;

          a && b ===>  若a为假,则b将没有执行的机会;

          a || b ===>  若a为真,则b将没有执行的机会;

     3)操作符重载是靠函数重载来完成的;

     4)操作数作为函数参数传递;

     5)C++的函数参数都会被求值,无法实现短路规则;


五、C++不可以重载的运算符有:

       (1)?:    、   (2)::     、     (3).       、   (4).*


六、模板类中重载输入输出(>>、<<)运算符:

(1)在类外部实现时注意:

template <typename T>  
ostream & operator<< (ostream& out, const MyVector<T>& v)     //此处加<T>去具体化MyVector  
  
    for (int i = 0; i < v.m_len; i++)  
      
        out << v.m_space[i] << " ";  
      
    out << endl;  
    return out;  
  


C++运算符重载总结——转自:

https://wuyuans.com/2012/09/cpp-operator-overload/

1.一般运算符重载

在进行对象之间的运算时,程序会调用与运算符相对应的函数进行处理,所以运算符重载有两种方式:成员函数和友元函数。成员函数的形式比较简单,就是在类里面定义了一个与操作符相关的函数。友元函数因为没有this指针,所以形参会多一个。
 
  1. class A
  2. public:
  3. A(int d):data(d)
  4. A operator+(A&);//成员函数
  5. A operator-(A&);
  6. A operator*(A&);
  7. A operator/(A&);
  8. A operator%(A&);
  9. friend A operator+(A&,A&);//友元函数
  10. friend A operator-(A&,A&);
  11. friend A operator*(A&,A&);
  12. friend A operator/(A&,A&);
  13. friend A operator%(A&,A&);
  14. private:
  15. int data;
  16. ;
  17. //成员函数的形式
  18. A A::operator+(A &a)
  19. return A(data+a.data);
  20. A A::operator-(A &a)
  21. return A(data-a.data);
  22. A A::operator*(A &a)
  23. return A(data*a.data);
  24. A A::operator/(A &a)
  25. return A(data/a.data);
  26. A A::operator%(A &a)
  27. return A(data%a.data);
  28. //友元函数的形式
  29. A operator+(A &a1,A &a2)
  30. return A(a1.data+a2.data);
  31. A operator-(A &a1,A &a2)
  32. return A(a1.data-a2.data);
  33. A operator*(A &a1,A &a2)
  34. return A(a1.data*a2.data);
  35. A operator/(A &a1,A &a2)
  36. return A(a1.data/a2.data);
  37. A operator%(A &a1,A &a2)
  38. return A(a1.data%a2.data);
  39. //然后我们就可以对类的对象进行+、-、*、/了。
  40. void main(void)
  41. A a1(1),a2(2),a3(3);
  42. a1=a2+a3;
  43. //或者
  44. a1=a2.operator+(a3);

注意:在进行a2+a3的时候会出错,因为我们在上面对+定义了两种方法,去掉一种即可。

2.关系运算符重载

因为函数体比较简单, 后面我就只给出成员函数形式的函数声明了,关系运算符有==,!=,<,>,<=,>=。
 
  1. bool operator == (const A& );
  2. bool operator != (const A& );
  3. bool operator < (const A& );
  4. bool operator <= (const A& );
  5. bool operator > (const A& );
  6. bool operator >= (const A& );

3.逻辑运算符重载

 
  1. bool operator || (const A& );
  2. bool operator && (const A& );
  3. bool operator ! ();

4.单目运算符重载

这里的+、-是正负的意思,放在对象前面。
 
  1. A& operator + ();
  2. A& operator - ();
  3. A* operator & ();
  4. A& operator * ();

5.自增减运算符重载

++和–根据位置的不同有四种情况,都可以重载。

(前置:改变了自身,所以返回引用合适;)

(后置:只是返回自身原来的一个副本,所以返回一个值合适;)

 
  1. A& operator ++ ();//前置++
  2. A operator ++ (int);//后置++
  3. A& operator --();//前置--
  4. A operator -- (int);//后置--

6.位运算符重载

按位操作。
 
  1. A operator | (const A& );
  2. A operator & (const A& );
  3. A operator ^ (const A& );
  4. A operator << (int i);
  5. A operator >> (int i);
  6. A operator ~ ();

7.赋值运算符重载

没有=哦。
 
  1. A& operator += (const A& );
  2. A& operator -= (const A& );
  3. A& operator *= (const A& );
  4. A& operator /= (const A& );
  5. A& operator %= (const A& );
  6. A& operator &= (const A& );
  7. A& operator |= (const A& );
  8. A& operator ^= (const A& );
  9. A& operator <<= (int i);
  10. A& operator >>= (int i);

8.内存运算符重载

 
  1. void *operator new(size_t size);
  2. void *operator new(size_t size, int i);
  3. void *operator new[](size_t size);
  4. void operator delete(void*p);
  5. void operator delete(void*p, int i, int j);
  6. void operator delete [](void* p);

9.特殊运算符重载

上面的运算符重载都有两种方式,而下面的运算符只能用一种,特殊吧。这些运算符的重载只能是成员函数。
 
  1. A& operator = (const A& );
  2. char operator [] (int i);//返回值不能作为左值
  3. const char* operator () ();
  4. T operator -> ();
  5. //类型转换符
  6. operator char* () const;
  7. operator int ();
  8. operator const char () const;
  9. operator short int () const;
  10. operator long long () const;
  11. //还有很多就不写了

而这些只能以友元函数的形式重载

 
  1. friend inline ostream &operator << (ostream&, A&);//输出流
  2. friend inline istream &operator >> (istream&, A&);//输入流

10.总结

两种重载方式的比较:
  • 一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。
  • 以下一些双目运算符不能重载为类的友元函数:=、()、[]、->。
  • 类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。 C++提供4个类型转换函数:reinterpret_cast(在编译期间实现转换)、const_cast(在编译期间实现转换)、stactic_cast(在编译期间实现转换)、dynamic_cast(在运行期间实现转换,并可以返回转换成功与否的标志)。
  • 若一个运算符的操作需要修改对象的状态,选择重载为成员函数较好。
  • 若运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选用友元函数。
  • 当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部 类型的对象,该运算符函数必须作为一个友元函数来实现。
  • 当需要重载运算符具有可交换性时,选择重载为友元函数。
注意事项:
  1. 除了类属关系运算符”.“、成员指针运算符”.*“、作用域运算符”::“、sizeof运算符和三目运算符”?:“以外,C++中的所有运算符都可以重载。
  2. 重载运算符限制在C++语言中已有的运算符范围内的允许重载的运算符之中,不能创建新的运算符。
  3. 运算符重载实质上是函数重载,因此编译程序对运算符重载的选择,遵循函数重载的选择原则。
  4. 重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符操作数的个数及语法结构。
  5. 运算符重载不能改变该运算符用于内部类型对象的含义。它只能和用户自定义类型的对象一起使用,或者用于用户自定义类型的对象和内部类型的对象混合使用时。
  6. 运算符重载是针对新类型数据的实际需要对原有运算符进行的适当的改造,重载的功能应当与原有功能相类似,避免没有目的地使用重载运算符。

以上是关于操作符(运算符)重载注意事项(含模板类中<<;;重载)的主要内容,如果未能解决你的问题,请参考以下文章

尝试在模板类中重载 / 运算符的 C++ 错误

模板类和插入提取重载

基于模板类开发vector容器

基于模板类开发vector容器

如何在具有动态大小数组的模板类中重载 operator=

如何重载模板类的“新”运算符?