首页 > 编程语言 > 详细

C++——使用类

时间:2015-07-10 20:30:57      阅读:264      评论:0      收藏:0      [点我收藏+]

 

一、运算符重载

  1、运算符重载

  C++允许将运算符重载扩展到用户定义的类型。

  要重载运算符,需使用被称为运算符函数的特殊函数形式。运算符函数的格式如下:

     operatorop(argument list);

  例如,operator+()重载+运算符,operator*()重载*运算符。op必须是一个有效的C++运算符,不能虚构一个新的符号。

  例如,将Person对象的体重相加,如果per1、per2和perSum都是Person对象,便可编写这样的等式:

      perSum = per1 + per2;

  编译器发现,操作数是Person对象,因此使用相应的运算符函数替换上述运算符:

      perSum = per1.operator+(per2);

  然后该函数将隐式地使用per1对象(因为它调用了方法),显式地使用per2对象(因为他被作为参数传递),来计算总和,并返回这个值。

Time.h

 1 #include <stdio.h>
 2 class Time{
 3 private:
 4     int _hour;
 5     int _min;
 6     int _sec;
 7 public:
 8     Time(int hour = 0, int min = 0, int sec = 0);
 9     void setHour(int hour);
10     void setMin(int min);
11     void setSec(int sec);
12     int getHour() const;
13     int getMin() const;
14     int getSec() const;
15     void showTime() const;
16     Time operator+(const Time &time) const;
17 };

 

Time.cpp

 1 #include "Time.h"
 2 #include <iostream>
 3 Time::Time(int hour, int min, int sec){
 4     _hour = hour;
 5     _min = min;
 6     _sec = sec;
 7 }
 8 void Time::setHour(int hour){
 9     _hour = hour;
10 }
11 void Time::setMin(int min){
12     _min = min;
13 }
14 void Time::setSec(int sec){
15     _sec = sec;
16 }
17 int Time:: getHour() const{
18     return _hour;
19 }
20 int Time:: getMin() const{
21     return _min;
22 }
23 int Time:: getSec() const{
24     return _sec;
25 }
26 Time Time::operator+(const Time &time) const{
27     int hour, min, sec, min_, hour_;
28     sec = (_sec + time.getSec())%60;
29     min_ = (_sec + time.getSec())/60;
30     
31     min = (_min + time.getMin() + min_)%60;
32     hour_ = (_min + time.getMin() + min_)/60;
33     
34     hour = (_hour + time.getHour() + hour_)%24;
35     return Time{hour,min,sec};
36 }
37 void Time:: showTime()const{
38     printf("时间:%02d:%02d:%02d\n",_hour,_min,_sec);
39 }

 

main.app

 1 #include <iostream>
 2 #include "Time.h"
 3 
 4 int main(int argc, const char * argv[]) {
 5     Time t1{8,12,45};
 6     Time t2{18,45,25};
 7     Time t3 = t1 + t2;
 8     t3.showTime();
 9     t3 = t3 + t1 + t2;
10     t1.showTime();
11     t2.showTime();
12     t3.showTime();
13   
14     return 0;
15 }

 

 

输出结果:

1 时间:02:58:10
2 时间:08:12:45
3 时间:18:45:25
4 时间:05:56:20

 

 

   注意:在运算符表示法中,运算符左侧的对象是调用对象,运算符右侧的对象是作为参数被传递的对象。  

  

  2、运算符重载限制

    重载的运算符(有些情况例外)不必是成员函数,但至少有一个操作数是用户定义的类型。对于非成员运算符重载函数来说,运算符表达式左边的操作数对应于运算符函数的第一个参数,运算符表达式右边的操作数对应于运算符函数的第二个参数。

 1 #include <iostream>
 2 #include "Time.h"
 3 Time operator-(const Time &,const Time &);//非成员运算符重载函数
 4 void operator-=(Time &time1,const Time & time);
 5 int main(int argc, const char * argv[]) {
 6     Time t1{8,12,45};
 7     Time t2{18,45,25};
 8     Time t3 = t1 + t2;
 9     t3.showTime();
10     t3-= t2;
11     t3.showTime();
12     t3 -=t1;
13     t3.showTime();
14     
15     return 0;
16 }
17 Time operator-( const Time & time1,const Time& time2){
18     int hour = time1.getHour();
19     int min = time1.getMin();
20     int sec = time1.getSec();
21     if (sec < time2.getSec()) {
22         min--;
23         sec = sec + 60 - time2.getSec();
24     }
25     else
26         sec -= time2.getSec();
27     if (min < time2.getMin()) {
28         hour--;
29         min = min + 60 - time2.getMin();
30     }
31     else
32         min -= time2.getMin();
33     if (hour < time2.getHour()) {
34         hour = hour - time2.getHour() + 24;
35     }
36     else
37         hour -= time2.getHour();
38     
39     return Time{hour,min,sec};
40 }
41 void operator-=( Time &time1,const Time & time){
42     time1 = time1 - time;
43 }

 

  

  下面详细介绍C++对用户定义的运算符重载的限制:

    (1)重载后的运算符必须至少有一个操作数是用户定义的类型,这将防止用户为标准类型重载运算符。

    (2)使用运算符时不能违反运算符原来的句法规则。例如,不能将%重载成使用一个操作数。同样,不能修改运算符的优先级。

    (3)不能创建新的运算符。

    (4)不能重载下面的运算符:

        *  sizeof:szieof运算符;

        *  . :成员运算符(.);

        *  .* : 成员指针运算符;

        *  :: :作用域运算符;

        *  ?: :条件运算符;

        *  typeid:一个RTTI运算符;

        *  const_cast :强制类型转换运算符;

        *  dynamic_cast :强制类型转换运算符;

        *  reinterpret_cast:强制类型转换运算符;

        * static_cast : 强制类型转换运算符;

     (5)下面标中的运算符都可以被重载

                                    可重载的运算符

+ - * / % ^
& | ~= ! = <
> += -= *= /= %=
^= &= |= << >> >>=
<<= == != <= >= &&
|| ++ -- , ->* ->
() [] new delete new[] delete[]

      但是下面的运算符只能通过成员函数进行重载:赋值运算符(=)、函数调用运算符(())、下标运算符([])、通过指针访问类成员的运算符(->)。 

 

二、友元

  友元有三种:友元函数、友元类、友元成员函数。

  

  1、友元函数

  通过让函数成为类的友元,可以赋予该函数与类的成员函数相同访问权限。

  由于成员运算符函数重载运算符后,该运算符左边的操作数只能是该对象;然而,当其他类型的操作数与对象运算时,如果其他类型操作数在运算符的左边,例如2*time(其中time为类对象),将会出现错误,因为其他类型的操作数无法调用对象的成员运算符重载函数。这时,可以声明定义非成员运算符重载函数,把函数的第一个参数设置为其他类型的参数,这样就可以与对象的成员运算符重载函数相配合,实现与2*time相似的表达式。

Time类中*的成员运算符重载函数的定义:

1 Time Time::operator*(unsigned int num)const{
2     int hour,min,sec;
3     sec = _sec * num;
4     min = _min * num + sec/60;
5     hour = _hour * num + min /60;
6     min %= 60;
7     sec %= 60;
8     return Time{hour,min,sec};
9 }

 

main.cpp:

 1 #include <iostream>
 2 #include "Time.h"
 3 Time operator*(unsigned int , const Time &);
 4 int main(int argc, const char * argv[]) {
 5     Time t1{2,25,30};
 6     Time t2 = t1 * 2;//将会调用成员运算符重载函数
 7     Time t3 = 3 * t1;//将会调用非成员运算符重载函数
 8     using std::cout;
 9     cout << "t1";
10     t1.showTime();
11     cout << "t2";
12     t2.showTime();
13     cout << "t3";
14     t3.showTime();
15     
16     return 0;
17 }
18 Time operator*(unsigned int num, const Time & time){
19     int hour, min,sec;
20     sec = time.getSec() * num;
21     min = time.getMin() * num + sec /60;
22     hour = time.getHour() * num + min/60;
23     sec %= 60;
24     min %= 60;
25     return Time{hour,min,sec};
26 }
27 
28 输出结果:
29 t1时间:02小时25分30秒
30 t2时间:04小时51分00秒
31 t3时间:07小时16分30秒

 

  使用非成员函数可以按所需要的顺序获得操作数,但引发了一个新问题:常规非成员函数不能访问类的私有数据。C++提供了友元函数,一种特殊的非成员函数,可以访问类的私有数据。

  (1)创建友元

    第一步,将原型放在类声明中,并在原型声明前加上关键字friend。这样声明的函数原型,意味着一下两点:

      *虽然该函数原型是在类声明中声明的,但是他不是类的成员函数,因此不能使用成员运算符来调用;

      *虽然该函数不是类的成员函数,但它与成员函数的访问权相同。

    第二部,编写函数定义。因为友元函数不是成员函数,因此不能使用类作用域限定符。另外,也不要在定义中使用关键字friend。

  现在,对上面的Time对象乘以整数的例子进行改进:

Time.h文件:

 1 #include <stdio.h>
 2 class Time{
 3 private:
 4     int _hour;
 5     int _min;
 6     int _sec;
 7 public:
 8     Time(int hour = 0, int min = 0, int sec = 0);
 9     int getHour() const;
10     int getMin() const;
11     int getSec() const;
12     void showTime() const;
13     Time operator*(unsigned int num) const;//声明成员运算符重载函数
14     friend Time operator*(unsigned int, const Time &);//声明友元运算符重载函数
15 };

 

 

 

Time.cpp源文件:

 1 #include "Time.h"
 2 #include <iostream>
 3 Time::Time(int hour, int min, int sec){
 4     _hour = hour;
 5     _min = min;
 6     _sec = sec;
 7 }
 8 int Time:: getHour() const{
 9     return _hour;
10 }
11 int Time:: getMin() const{
12     return _min;
13 }
14 int Time:: getSec() const{
15     return _sec;
16 }
17 void Time:: showTime()const{
18     printf("时间:%02d小时%02d分%02d秒\n",_hour,_min,_sec);
19 }
20 Time Time::operator*(unsigned int num)const{//成员运算符重载函数的第一个操作数必须是该类对象
21     int hour,min,sec;
22     sec = _sec * num;
23     min = _min * num + sec/60;
24     hour = _hour * num + min /60;
25     min %= 60;
26     sec %= 60;
27     return Time{hour,min,sec};
28 }
29 Time operator*(unsigned int num, const Time &time){//通过友元函数进行反转,定义友元函数的时候不能包含类作用域限定符,也不要包含friend关键
30     return time * num;
31 }

 

main.cpp:

 1 #include <iostream>
 2 #include "Time.h"
 3 
 4 int main(int argc, const char * argv[]) {
 5     Time t1{2,25,30};
 6     Time t2 = t1 * 2;//将会调用成员运算符重载函数
 7     Time t3 = 3 * t1;//将会调用友元运算符重载函数
 8     using std::cout;
 9     cout << "t1";
10     t1.showTime();
11     cout << "t2";
12     t2.showTime();
13     cout << "t3";
14     t3.showTime();
15     
16     return 0;
17 }
18 
19 输出结果:
20 t1时间:02小时25分30秒
21 t2时间:04小时51分00秒
22 t3时间:07小时16分30秒

 

  提示:如果要为类重载运算符,并将非类的项作为第一个操作数,则可以使用友元函数来反转操作数的顺序。

  

  (2)常用的友元:重载<<运算符

    一个很有用的特性是,可以对<<运算符进行重载,使之能与cout一起来显示对象的内容。

      要使类知道使用cout,必须使用友元函数。因为像下面这样的语句使用两个对象,其中第一个是ostream类对象(cout):

          cout << trip;

      如果使用类成员函数来重载<<,类对象将是第一个操作数。就意味着应该这样使用<<:

          trip << cout;

      这样会使人迷惑。但是,通过友元函数,就可以反转操作数顺序。下面是在Time类中,实现友元<<运算符重载函数:

Time.h文件

 1 #include <ostream>
 2 
 3 class Time{
 4 private:
 5     int _hour;
 6     int _min;
 7     int _sec;
 8 public:
 9     Time(int hour = 0, int min = 0, int sec = 0);
10     int getHour() const;
11     int getMin() const;
12     int getSec() const;
13     Time operator*(unsigned int num) const;
14     friend Time operator*(unsigned int, const Time &);//声明友元函数
15     friend std::ostream& operator<<(std::ostream &, const Time &);//声明友元<<运算符重载函数
16 
17 };

 

Time.cpp文件:

 1 #include "Time.h"
 2 #include <iostream>
 3 Time::Time(int hour, int min, int sec){
 4     _hour = hour;
 5     _min = min;
 6     _sec = sec;
 7 }
 8 int Time:: getHour() const{
 9     return _hour;
10 }
11 int Time:: getMin() const{
12     return _min;
13 }
14 int Time:: getSec() const{
15     return _sec;
16 }
17 
18 Time Time::operator*(unsigned int num)const{//成员运算符重载函数的第一个操作数必须是该类对象
19     int hour,min,sec;
20     sec = _sec * num;
21     min = _min * num + sec/60;
22     hour = _hour * num + min /60;
23     min %= 60;
24     sec %= 60;
25     return Time{hour,min,sec};
26 }
27 Time operator*(unsigned int num, const Time &time){//通过友元函数进行反转,定义友元函数的时候不能包含类作用域限定符,也不要包含friend关键
28     return time * num;
29 }
30 std::ostream& operator<<(std::ostream &os, const Time &time){//定义友元<<运算符重载函数
31     os << time.getHour() << "小时" << time.getMin() << "" << time.getSec() << "";
32     return os;
33 }

 

main.cpp文件:

 1 #include <iostream>
 2 #include "Time.h"
 3 
 4 int main(int argc, const char * argv[]) {
 5     Time t1{2,25,30};
 6     Time t2 = t1 * 2;//将会调用成员*运算符重载函数
 7     Time t3 = 3 * t1;//将会调用友元*运算符重载函数
 8     std::cout << "t1:" << t1 << "\nt2:" << t2 << "\nt3:"  << t3;
 9     
10     return 0;
11 }
12 
13 输出结果:
14 t1:2小时25分30秒
15 t2:4小时51分0秒
16 t3:7小时16分30秒

 

  提示:一般来说,要重载<<运算符来显示c_name对象,可使用一个友元函数,其定义如下:

      ostream & oprator<<(ostream & os, const c_name & obj){

          os <<...;//显示对象的内容

          return os;

      }

 

三、重载运算符:作为成员函数还是非成员函数

    对于很多运算符来说,可以选择成员函数或非成员函数来实现运算符重载。一般来说,非成员函数应是友元函数,这样他才能访问类的私有数据。

    非成员版本的重载运算符函数所需的参数数目与运算符使用的操作数数目相同,所有的操作数作为函数参数显式地传递给非成员运算符重载函数;而成员版本所需的参数数目少一个,因为其中的一个参数是被隐式地传递的调用对象。

    在定义作用于类对象的运算符重载函数时,究竟是使用成员函数还是非成员函数还是两者都适用的选择依据有一下两点:

    (1)如果运算符的操作数类型一致,选择友元运算符重载函数或成员运算符重载函数中的一种,而不能同时选择这两种;否则将会报错。

    (2)如果运算符的操作数类型不一致,例如一个是内置类型,另一个是类对象,那么用成员运算符重载函数实现类对象在运算符左边的重载功能,然后用友元运算符重载函数反转操作数顺序。

 

四、再谈重载:一个矢量类

  

 

C++——使用类

原文:http://www.cnblogs.com/mupiaomiao/p/4636501.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!