思考: 对于一个要重载的运算符而言,什么样的运算符应该用类成员函数重载,什么情况应该用友元函数重载??

Posted 后营马族子弟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了思考: 对于一个要重载的运算符而言,什么样的运算符应该用类成员函数重载,什么情况应该用友元函数重载??相关的知识,希望对你有一定的参考价值。

还是用一个例子来说明吧

 1 #define unsigned int UINT32
 2 
 3 class RMB
 4 {
 5     public:
 6     RMB(UINT32 d, UINT32 c);
 7     friend RMB operator +(RMB&, RMB&);
 8     friend RMB& operator ++(RMB&);
 9     void display()
10     {
11         cout<<(yuan + jf / 100.0)<<endl;
12     }
13     
14     protected:
15     UINT32 yuan;      //
16     UINT32 jf;         //角分
17 };
18 
19 RMB::RMB(UINT32 d, UINT32 c) : yuan(d), jf(c)
20 {
21     while (jf >= 100)
22     {
23         yuan++;
24         jf -= 100;
25     }
26 }
27 
28 RMB operator +(RMB& rmb1, RMB& rmb2)
29 {
30     UINT32 jf = rmb1.jf + rmb2.jf;
31     UINT32 yuan = rmb1.yuan + rmb2.yuan;
32     return RMB(yuan, jf);
33 }
34 
35 RMB& operator ++(RMB& rmb)
36 {
37     s.jf++;
38     if (jf >= 100)
39     {
40         s.yuan++;
41         jf -= 100;
42     }
43     return rmb;
44 }
45 
46 int main()
47 {
48     RMB rmb1(1,60);
49     RMB rmb2(2, 50);
50     RMB rmb3(0,0);
51     rmb3 = rmb1 + rmb2;  //4, 10
52     ++rmb3;  //4, 11
53     
54     rmb3.display();
55     
56     return 0;
57 }
58 //问题思考:
//1.前++定义 A& operator++(xxx);--->xxx不是int就可以 后++定义: A operator++(int)
//2.第51行是可行的, 但是改为 rmb3 = 1.2 + rmb1 或者 rmb3 = 1.3 + 1.2 或者rmb3 = rmb1 + 1.2呢 是否还可以编译通过?

针对问题2,我们可以增加opertor的重载函数

    friend RMB operator +(double&, RMB&);
    friend RMB operator +(RMB&, double&);

但是这样很麻烦.

这里会利用类构造函数的隐式转换提供一个解决方案

 先用一个小例子来说明,隐式转换的用法
1
#include<iostream> 2 using namespace std; 3 4 class A 5 { 6 public: 7 A(double ii):i(ii){} 8 void print(A a) 9 { 10 cout<<a.i<<endl; 11 } 12 /* 13 void print(A& a) //如果是A&的话,外部的隐式转换将不可用 14 { 15 cout<<a.i<<endl; 16 } 17 */ 18 private: 19 double i; 20 }; 21 int main() 22 { 23 A a(3); 24 A b(4); 25 b.print(a); 26 b.print(5); //如果要使用隐式转换,print的形参必须不能使引用 27 return 0; 28 }

 

好,接下来我们来看看我们的代码

 1 #include<iostream>
 2 using namespace std;
 3 
 4 #define UINT32 unsigned int 
 5 
 6 class RMB
 7 {
 8     public:
 9         RMB(UINT32 d, UINT32 c);
10         RMB(double value);   //提供隐式转换构造函数
11         friend RMB operator +(RMB, RMB);  //从引用转为非引用
12 
13         friend RMB& operator ++(RMB&);
14         void display()
15         {
16             cout<<(yuan + jf / 100.0)<<endl;
17         }
18 
19     protected:
20         UINT32 yuan;    //
21         UINT32 jf;        //角分
22 };
23 
24 RMB::RMB(UINT32 d, UINT32 c) : yuan(d), jf(c)
25 {
26     while (jf >= 100)
27     {
28         yuan++;
29         jf -= 100;
30     }
31 }
32 
33 RMB::RMB(double value)
34 {
35     yuan = static_cast<int>(value);
36     jf = static_cast<int>( (value - yuan) * 100 + 0.5);  //+0.5是为了完成四舍五入. 
37 }
38 
39 RMB operator +(RMB rmb1, RMB rmb2)    //从引用改为非引用
40 {
41     UINT32 jf = rmb1.jf + rmb2.jf;
42     UINT32 yuan = rmb1.yuan + rmb2.yuan;
43     return RMB(yuan, jf);
44 }
45 
46 RMB& operator ++(RMB& rmb)
47 {
48     RMB& s = rmb;
49     s.jf++;
50     if (s.jf >= 100)
51     {
52         s.yuan++;
53         s.jf -= 100;
54     }
55     return rmb;
56 }
57 
58 int main()
59 {
60     RMB rmb1(1,60);
61     RMB rmb2(2, 50);
62     RMB rmb3(0,0);
63     rmb3 = rmb1 + rmb2;  
64     ++rmb3;
65     rmb3.display();
66 
67     RMB rmb4(1.2);
68     rmb4.display();
69 
70     rmb3 = 1.2 + rmb1;
71     rmb3.display();
72 
73     rmb3 = 1.2 + 1.3;
74     rmb3.display();
75 
76     rmb3 = rmb1 + 1.2;
77     return 0;
78 }

那好,我们看到.我们所在的变化是a.提供了一个隐式转换构造函数, b.把友元+的重载函数的形参从引用改为了非引用(会导致效率变低).

如果我们提供 frind operator +(double, RMB&)  friend operator+(RMB&, double), friend operator+(doube, double)的话倒是不用把引用改为非引用,但是问题是会导致要写很多个重载函数.. 所以如果把引用该为非引用而引起的效率变化不太大的情况下,建议用第一种方法

 

--------------------------------------------------------------------------------------------------------------------------------------------------------

接下来,我们再来分析一下 重载函数+ 使用成员函数来实现的方式

先看 rmb3 = rmb1 + rmb2的情况的代码

 1 #include<iostream>
 2 using namespace std;
 3 
 4 #define UINT32 unsigned int 
 5 
 6 class RMB
 7 {
 8     public:
 9         RMB(UINT32 d, UINT32 c);
10         RMB operator +(RMB& rmb);
11         RMB& operator ++();
12         void display()
13         {
14             cout<<(yuan + jf / 100.0)<<endl;
15         }
16 
17     protected:
18         UINT32 yuan;    //
19         UINT32 jf;        //角分
20 };
21 
22 RMB::RMB(UINT32 d, UINT32 c) : yuan(d), jf(c)
23 {
24     while (jf >= 100)
25     {
26         yuan++;
27         jf -= 100;
28     }
29 }
30 
31 RMB RMB::operator +(RMB& rmb)
32 {
33     UINT32 newJf = jf + rmb.jf;
34     UINT32 newYuan = yuan + rmb.yuan;
35     return RMB(newYuan, newJf);
36 }
37 
38 RMB& RMB::operator ++()
39 {
40     jf++;
41     if (jf >= 100)
42     {
43         yuan++;
44         jf -= 100;
45     }
46     return *this;
47 }
48 
49 int main()
50 {
51     RMB rmb1(1,60);
52     RMB rmb2(2, 50);
53     RMB rmb3(0,0);
54     rmb3 = rmb1 + rmb2;  
55     ++rmb3;
56     rmb3.display();
57     return 0;
58 }

然后我们再来考虑考虑  一下集中情况在运算符是成员函数的情况下是否可行

rmb3 = 1.2 + rmb1 ------------------->绝对实现不了.因为1.2(double)类型中没有重载一个+号可以加上一个RMB类型

rmb3 = rmb1 + 1.2--------------------->可行,我可以重载一个 RMB& operater +(double);

rmb3 = 1.2 + 1.1------------------------>不可行.1.2+1.3是两个double类型的相加,然后把一个double类型用重载符号=赋值给rmb3.

看来,在非类对象和操作符组合的时候,成员函数实现的运算符重载和友元函数实现的运算符重载还是有区别的啊,不可不察..

ps:

//c++ 规定: = () [] ->这四种运算符必须是成员形式
//某些双目运算符在使用非成员的形式(如复数类的+,-运算符)有肯能是为了实现某些隐式转换或者成员形式无法进行的操作(例如上面的 rmb3 = 1.2+rmb1).而特意选用的非成员形式.

 

以上是关于思考: 对于一个要重载的运算符而言,什么样的运算符应该用类成员函数重载,什么情况应该用友元函数重载??的主要内容,如果未能解决你的问题,请参考以下文章

学习:类和对象——运算符重载

什么运算符一定要重载友元函数,什么时候一定要重载为成员函数?

重载运算符

STL重载运算符

重载运算符

有关重载运算符的一些思考