• C++第十一章__用类方法合并另个时间(涉及到函数返回值能不能是引用的问题)__运算符重载__友元函数__对<<运算符的重载&友元函数__ cin.clear()的用法__极坐标和直角坐标的相互转换(随机漫步的实现)__将double、int等数据类型赋值给类对象__将类对象赋值给double、int等型的变量(转换函数)


    ---恢复内容开始---

    目录

    用类方法合并另个时间&运算符重载(涉及到函数返回值能不能是引用的问题)

    用类方法合并另个时间的代码如下:

     1 //mytime.h
     2 #ifndef MYTIME_H_
     3 #define MYTIME_H_
     4 
     5 class Time
     6 {
     7 private:
     8     int hour;
     9     int minitue;
    10 public:
    11     Time();  //声明默认构造函数
    12     //Time(int & h, int & m);  //声明构造函数,如果是这样声明构造函数的话,在主函数中调用构造函数,传入一个数字是不合法的
    13     Time(int  h, int  m);  //声明构造函数
    14     Time Sum(Time & T);  //声明返回值为类对象的函数,形参为指向类对象的引用
    15     void Addhour(int h);  //单独的增加小时
    16     void Addminitue(int m);  //单独的增加分钟
    17     void Reset(int h=0, int m=0);  //重置时间
    18     void show();
    19 };
    20 
    21 #endif
    mytime.h
     1 //mytime.cpp
     2 #include <iostream>
     3 #include "mytime.h"
     4 
     5 Time::Time()  //默认构造函数的定义,创建类对象时,默认执行以下操作
     6 {
     7     hour = 0;
     8     minitue = 0;
     9 }
    10 
    11 
    12 /*Time::Time(int & h, int & m) *///构造函数定义,创建类对象时,使用构造函数时执行以下操作.
    13 //声明构造函数,如果是这样声明构造函数的话,在主函数中调用构造函数,传入一个数字是不合法的
    14 //即 int & h = 4;  这样是不合法的
    15 Time::Time(int  h, int  m)  //这样在声明类对象的时候,调用该构造函数才是合法的,因为将数字传递给引用是不合法的
    16 {
    17     hour = h;
    18     minitue = m;
    19 }
    20 
    21 Time Time::Sum(Time & T)
    22 {
    23     Time s;  //新建一个TIme对象,用于作为该函数的返回值
    24     s.minitue = minitue + T.minitue;
    25     s.hour = hour + T.hour + s.minitue / 60; 
    26     //hour是调用Sum()方法的对象中的数据,T.hour是作为实参传入的对象中的数据
    27     //最后再加上调用对象的分钟数,和,作为实参传入的分钟数的和,然后取整
    28     s.minitue = s.minitue % 60;  //对两个对象中数据的分钟数取余
    29 
    30     return s;
    31 }
    32 //注意:Sum()函数的返回值不能是Time & (指向Time对象的引用),这是由于返回的对象时s,而s是一个在Sum()
    33 //中定义的局部变量,Sum()函数执行完毕后,s将会消失,返回一个消失的引用是不合适的
    34 //所以这里返回s对象的副本,之后在主函数中可以使用它 
    35 //以前函数的返回值可以为引用,是因为返回的对象均为从主函数中传入的对象,这些对象都是在主函数中定义的
    36 //所以可以返回,比如this指针那里,传入一个对象和this指针指向的调用类方法的对象
    37 
    38 //只是增加小时
    39 void Time::Addhour(int h)
    40 {
    41     hour = hour + h;
    42 }
    43 
    44 //只是增加分钟
    45 void Time::Addminitue(int m)
    46 {
    47     minitue = minitue + m;
    48     hour = hour + minitue / 60;  //如果增加的分钟数超过了60则对minitue以60为底取整
    49     minitue = minitue % 60;  //如果增加的分钟数超过了60则对minitue以60为底取余
    50 }
    51 
    52 //重置时间
    53 void Time::Reset(int h, int m)
    54 {
    55     hour = h;
    56     minitue = m;
    57 }
    58 
    59 //显示对象中的数据
    60 void Time::show()
    61 {
    62     std::cout << "hour= " << hour << " minitue= " << minitue << std::endl;
    63 }
    mytime.cpp
     1 //user_main.cpp
     2 #include <iostream>
     3 #include "mytime.h"
     4 
     5 int main()
     6 {
     7     Time s1;  //定义一个Time类对象,并用默认构造函数进行初始化
     8     Time s2(2, 40);  //定义一个Time类对象,并隐式的调用构造函数
     9     Time s3(5, 55);  //定义一个Time类对象,并隐式的调用构造函数
    10 
    11     s1 = s2.Sum(s3); //将Sum()中的this指向s2,s形参用实参s3代替
    12     s1.show();
    13 
    14     s1.Addhour(3);  //对s1对象中的数据,只是增加小时
    15     s1.show();
    16 
    17     system("pause");
    18     return 0;
    19 }
    20 /* 总结 */
    21 /*
    22 01)关于引用的使用方法:int & rt = 3; 这样使用是不合法的,要注意在函数参数传递的时候不要发生这样的错误
    23 02)关于函数返回值的问题:如果一个变量(包括对象)是在该函数内创建的,那么是不可以以引用的方式返回的
    24    因为引用返回的都是该变量本身,而该变量在对应的函数执行完毕之后就消失了,从而发生错误。
    25    但是如果变量(对象)是从主函数中传入的,并且返回的也是从主函数中传入的变量(对象),那么是可以以引用
    26    的方式返回的。
    27 03)
    28 */
    user_main.cpp

    /* 总结 */
    01)关于引用的使用方法:int & rt = 3; 这样使用是不合法的,要注意在函数参数传递的时候不要发生这样的错误
    02)关于函数返回值的问题:如果一个变量(包括对象)是在该函数内创建的,那么是不可以以引用的方式返回的
         因为引用返回的都是该变量本身,而该变量在对应的函数执行完毕之后就消失了,从而发生错误。
         但是如果变量(对象)是从主函数中传入的,并且返回的也是从主函数中传入的变量(对象),那么是可以以引用
         的方式返回的。

     执行结果:

    运算符重载 

    01)要使用重载运算符,必须使用被称为运算符函数的特殊函数形式:
       operaterop(argument-list)
       其中operater为关键字,op是要重载的运算符,argument-list为形参,相当于创建一个名字为operaterop的函数
       比如对+进行重载即:operater+(),该函数没有形参
       op必须是有效的C++运算符,不能是@,但可以是[],因为[]是数组索引运算符
    02)运算符重载实际上仍然是函数调用,只不过换了一种形式
       假如对+进行重载即:operater+(Time & s) 其中Time是一个类
       那么就可以说使用如下方式对两个对象进行相加:
       s1 = s2 + s3; //其中s1、s2、s3都是Time类对象
       编译器发现s1 s2 s3都是类对象,因此使用相应的运算符函数进行替换:
       s1 = s2.operater+(s3); //所以说运算符重载实际上也还是函数调用
    03)s1 = s2 + s3;该式隐式的使用s2(因为s2调用了类方法),显式的使用了类对象s3(因为s3作为参数传入)
       当然s1 = s3 + s2; 也是可以的,因为s2和s3都是类对象
       上句就相当于s1 = s3.operater+(s2);了,即s3调用方法,s2作为参数传入

    /*  时间的运算,引入了+运算符重载、-运算符重载和*运算符重载  */

     1 //mytime.h
     2 //使用运算符重载版本
     3 //用 Time operater+(Time & s) const 代替Time Sum(Time & T);即可
     4 #ifndef MYTIME_H_
     5 #define MYTIME_H_
     6 
     7 class Time
     8 {
     9 private:
    10     int hour; 
    11     int minitue;
    12 public:
    13     Time();  //声明默认构造函数
    14     Time(int  h, int  m);  //声明构造函数
    15     Time operator+(const Time & T) const;  //对运算符进行重载,形参为执行类对象的引用,返回值为Time对象,
    16     //const Time & T 表明方法operator+()也不能修改作为参数传入的对象中的数据
    17     //最后一个const表明operater+()方法不能修改调用这个方法的对象中的数据
    18     Time operator-(const Time & T) const; //两个const可有可无
    19     Time operator*(double d) const;  //最后一个const还是表明不能修改调用operator*()方法的对象中的数据
    20     void Addhour(int h);  //单独的增加小时
    21     void Addminitue(int m);  //单独的增加分钟
    22     void Reset(int h=0, int m=0);  //重置时间
    23     void show();
    24 };
    25 
    26 #endif
    27 
    28 /* 运算符重载 */
    29 /*
    30 01)要使用重载运算符,必须使用被称为运算符函数的特殊函数形式:
    31    operaterop(argument-list)  
    32    其中operater为关键字,op是要重载的运算符,argument-list为形参,相当于创建一个名字为operaterop的函数
    33    比如对+进行重载即:operater+(),该函数没有形参
    34    op必须是有效的C++运算符,不能是@,但可以是[],因为[]是数组索引运算符
    35 02)运算符重载实际上仍然是函数调用,只不过换了一种形式
    36    假如对+进行重载即:operater+(Time & s)  其中Time是一个类
    37    那么就可以说使用如下方式对两个对象进行相加:
    38    s1 = s2 + s3;  //其中s1、s2、s3都是Time类对象
    39    编译器发现s1 s2 s3都是类对象,因此使用相应的运算符函数进行替换:
    40    s1 = s2.operater+(s3);  //所以说运算符重载实际上也还是函数调用
    41 03)s1 = s2 + s3;该式隐式的使用s2(因为s2调用了类方法),显式的使用了类对象s3(因为s3作为参数传入)
    42    当然s1 = s3 + s2; 也是可以的,因为s2和s3都是类对象
    43    上句就相当于s1 = s3.operater+(s2);了,即s3调用方法,s2作为参数传入
    44 
    45 */
    mytime.h
     1 //mytime.cpp
     2 //使用运算符重载版本
     3 //用 Time operater+(Time & s) const 代替Time Sum(Time & T);即可
     4 //重载-运算符Time Time::operator-(const Time & T) const 
     5 //重载*运算符Time Time::operator*(double d) const
     6 #include <iostream>
     7 #include "mytime.h"
     8 
     9 Time::Time()  //默认构造函数的定义,创建类对象时,默认执行以下操作
    10 {
    11     hour = 0;
    12     minitue = 0;
    13 }
    14 
    15 
    16 /*Time::Time(int & h, int & m) *///构造函数定义,创建类对象时,使用构造函数时执行以下操作.
    17 //声明构造函数,如果是这样声明构造函数的话,在主函数中调用构造函数,传入一个数字是不合法的
    18 //即 int & h = 4;  这样是不合法的
    19 Time::Time(int  h, int  m)  //这样在声明类对象的时候,调用该构造函数才是合法的,因为将数字传递给引用是不合法的
    20 {
    21     hour = h;
    22     minitue = m;
    23 }
    24 
    25 Time Time::operator+(const Time & T) const
    26 {
    27     Time s;  //新建一个TIme对象,用于作为该函数的返回值
    28     s.minitue = minitue + T.minitue;
    29     s.hour = hour + T.hour + s.minitue / 60; 
    30     //hour是调用Sum()方法的对象中的数据,T.hour是作为实参传入的对象中的数据
    31     //最后再加上调用对象的分钟数,和,作为实参传入的分钟数的和,然后取整
    32     s.minitue = s.minitue % 60;  //对两个对象中数据的分钟数取余
    33 
    34     return s;
    35 }
    36 //注意:Sum()函数的返回值不能是Time & (指向Time对象的引用),这是由于返回的对象时s,而s是一个在Sum()
    37 //中定义的局部变量,Sum()函数执行完毕后,s将会消失,返回一个消失的引用是不合适的
    38 //所以这里返回s对象的副本,之后在主函数中可以使用它 
    39 //以前函数的返回值可以为引用,是因为返回的对象均为从主函数中传入的对象,这些对象都是在主函数中定义的
    40 //所以可以返回,比如this指针那里,传入一个对象和this指针指向的调用类方法的对象
    41 
    42 //对-运算符进行重载
    43 Time Time::operator-(const Time & T) const 
    44 {
    45     Time s;  //创建一个局部对象,作为返回值
    46     s.minitue = minitue - T.minitue;  
    47     s.hour = hour - T.hour + s.minitue/60; //虽然是减,但是为了以防万一,还是加上这个取整吧
    48     s.minitue = s.minitue % 60;
    49 
    50     return s;
    51 }
    52 
    53 //对*运算符进行重载
    54 Time Time::operator*(double d) const
    55 {
    56     Time s;  //创建一个局部对象,作为返回值
    57     long total_time = hour * 60 * d + minitue * d;//这种都hour和minitue都相乘的方法是从书中学到的
    58     s.hour = total_time / 60;
    59     s.minitue = total_time % 60;  
    60 
    61     return s;
    62 }
    63 
    64 //只是增加小时
    65 void Time::Addhour(int h)
    66 {
    67     hour = hour + h;
    68 }
    69 
    70 //只是增加分钟
    71 void Time::Addminitue(int m)
    72 {
    73     minitue = minitue + m;
    74     hour = hour + minitue / 60;  //如果增加的分钟数超过了60则对minitue以60为底取整
    75     minitue = minitue % 60;  //如果增加的分钟数超过了60则对minitue以60为底取余
    76 }
    77 
    78 //重置时间
    79 void Time::Reset(int h, int m)
    80 {
    81     hour = h;
    82     minitue = m;
    83 }
    84 
    85 //显示对象中的数据
    86 void Time::show()
    87 {
    88     std::cout << "hour= " << hour << " minitue= " << minitue << std::endl;
    89 }
    mytime.cpp
     1 //user_main.cpp
     2 //使用运算符重载版本
     3 //用s1=s2+s3代替s1 = s2.Sum(s3);即可
     4 //s1=s2+s3;实际上是调用函数的方法:s1=s2.operator+(s3);
     5 #include <iostream>
     6 #include "mytime.h"
     7 
     8 int main()
     9 {
    10     Time s1;  //定义一个Time类对象,并用默认构造函数进行初始化
    11     Time s2(2, 40);  //定义一个Time类对象,并隐式的调用构造函数
    12     Time s3(5, 55);  //定义一个Time类对象,并隐式的调用构造函数
    13 
    14     std::cout << "使用+重载运算符:" << std::endl;
    15     s1 = s2 + s3; //等价于s1=s2.operator+(s3); s2和s3可以互换位置
    16     s1.show();
    17 
    18     std::cout << "使用类方法Addhour():" << std::endl;
    19     s1.Addhour(3);  //对s1对象中的数据,只是增加小时
    20     s1.show();
    21 
    22     std::cout << "使用-运算符重载方法:" << std::endl;
    23     s1 = s1 - s2;  //等价于s1=s1.operator-(s2);s1和s2可以互换位置
    24     s1.show();
    25 
    26     std::cout << "使用*运算符重载方法:" << std::endl;
    27     s1 = s1 * 2;   //等价于s1 = s1.operator-(2);
    28     s1.show();
    29     //这里s1只能是在*的左边,2只能是在*的右边
    30     //在*的左边的标识符是要调用operator*()方法的,显然数字不能调用该方法
    31     //此项缺陷也为以后的友元函数的提出打下了基础
    32 
    33     system("pause");
    34     return 0;
    35 }
    36 /* 总结 */
    37 /*
    38 01)关于引用的使用方法:int & rt = 3; 这样使用是不合法的,要注意在函数参数传递的时候不要发生这样的错误
    39 02)关于函数返回值的问题:如果一个变量(包括对象)是在该函数内创建的,那么是不可以以引用的方式返回的
    40    因为引用返回的都是该变量本身,而该变量在对应的函数执行完毕之后就消失了,从而发生错误。
    41    但是如果变量(对象)是从主函数中传入的,并且返回的也是从主函数中传入的变量(对象),那么是可以以引用
    42    的方式返回的。
    43 03)
    44 */
    user_main.cpp

    执行结果为:

     友元函数

    01)问题的提出:
      对于上一个代码中的对*的函数重载中 Time operator*(double d) const;
      对Time对象s1和s2,以及一个double值2.1
      使用方法只能是s1 = s2*2.1;//实际上是调用对*的重载函数:s1=s2.operator(2.1);
      所以s1 = 2.1*s2; 是会报错的
    02)解决方法:
      A 写注释:告诉每个人只能按照s2*2.1这种方式去写,不能写成2.1*s2
      B 使用非成员函数,非成员函数不是由对象调用的,它使用的值都必须是由实参的形式传入的
          但是也引发了一个新问题:非成员函数不能访问私有数据。最终的解决方法是使用友元函数

          此处引入友元函数的目的是实现乘法的交换律
    03)友元函数的声明方法:使用关键字friend
      friend Time operator*(doubla m,const Time & t);//该友元函数同时对*运算符进行了重载
      该声明意味着下面两点:
      A 虽然operator*()是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用; ***
      B 虽然operatir*()不是成员函数,但它有成员函数的访问权限。(可以访问私有数据)  ***
    04)友元函数的定义方法:不用使用关键字friend,因为它不是成员函数,所以也不用使用Time::限定符
      Time operator*(double m, Time & t) const
      {
        Time result;
        long total_time = t.hour * m + t.minitue * m;
        result.hour = total_time / 60;
        result.minitue = total_time % 60;
        return result;
         }
    05)友元函数调用方法:
     有了友元函数之后,就可以直接使用 s1 = 2.1*s2;
     编译器将s1 = 2.1*s2;转换成s1 = operator*(2.1,s2);友元函数版本
    06)稍作修改,就可以将友元函数改变成非友元函数:
        //在该非友元函数中调用对*的重载函数
      Time operator*(double m, Time & t) const
      {
        return t*m;  //即实际调用的函数为 t.operator*(m),即调用的函数是对*的重载的函数
        //原来的版本是显式的访问t.hour和t.minitue.由于这里是将对象t整体使用的,所以t*m将调用对*的重载函数
      }
    07)总结:
      如果在类声明中即声明了对*的重载函数Time operator*(double d) const;
      在类声明在又声明了友元函数:friend Time operator*(doubla m,const Time & t);
      该友元函数同时对*运算符进行了重载,那么在主函数中就可以使用下面的两种方式
      s1 = s2 * 2.1; //调用对*的重载函数,编译器将其转换为s1 = s2.operator(2.1);
      s1 = 2.1 * s2; //调用友元函数,编译器将其转换为:s1 = operator(2.1,s2);
      即实现了乘法的交换律。

     1 //mytime.h
     2 //使用运算符重载版本
     3 //用 Time operater+(Time & s) const 代替Time Sum(Time & T);即可
     4 #ifndef MYTIME_H_
     5 #define MYTIME_H_
     6 
     7 class Time
     8 {
     9 private:
    10     int hour; 
    11     int minitue;
    12 public:
    13     Time();  //声明默认构造函数
    14     Time(int  h, int  m);  //声明构造函数
    15     Time operator+(const Time & T) const;  
    16     Time operator-(const Time & T) const; //两个const可有可无
    17     Time operator*(double d) const;  //最后一个const还是表明不能修改调用operator*()方法的对象中的数据
    18     friend Time operator*(double m, const Time & t); //声明一个友元函数,只允许中声明的时候使用friend关键字
    19     void Addhour(int h);  //单独的增加小时
    20     void Addminitue(int m);  //单独的增加分钟
    21     void Reset(int h=0, int m=0);  //重置时间
    22     void show();
    23 };
    24 
    25 #endif
    26 
    27 
    28 /* 友元函数 */
    29 /*
    30 01)问题的提出:
    31    对于上一个代码中的对*的函数重载中 Time operator*(double d) const;
    32    对Time对象s1和s2,以及一个double值2.1
    33    使用方法只能是s1 = s2*2.1;//实际上是调用对*的重载函数:s1=s2.operator(2.1);
    34    所以s1 = 2.1*s2; 是会报错的
    35 02)解决方法:
    36    A 写注释:告诉每个人只能按照s2*2.1这种方式去写,不能写成2.1*s2
    37    B 使用非成员函数,非成员函数不是由对象调用的,它使用的值都必须是由实参的形式传入的
    38      但是也引发了一个新问题:非成员函数不能访问私有数据。最终的解决方法是使用友元函数
    39 03)友元函数的声明方法:使用关键字friend
    40    friend Time operator*(doubla m,const Time & t);//该友元函数同时对*运算符进行了重载
    41    该声明意味着下面两点:
    42    A 虽然operator*()是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用;
    43    B 虽然operatir*()不是成员函数,但它有成员函数的访问权限。(可以访问私有数据)
    44 04)友元函数的定义方法:不用使用关键字friend,因为它不是成员函数,所以也不用使用Time::限定符
    45    Time operator*(double m, Time & t) const
    46    {
    47        Time result;
    48        long total_time = t.hour * m + t.minitue * m;
    49        result.hour = total_time / 60;
    50        result.minitue = total_time % 60;
    51        return result;
    52    }
    53 05)友元函数调用方法:
    54    有了友元函数之后,就可以直接使用 s1 = 2.1*s2;
    55    编译器将s1 = 2.1*s2;转换成s1 = operator*(2.1,s2);友元函数版本
    56 06)稍作修改,就可以将友元函数改变成非友元函数:
    57    //在该非友元函数中调用对*的重载函数
    58    Time operator*(double m, Time & t) const  
    59    {
    60        return t*m; 
    61        //原来的版本是显式的访问t.hour和t.minitue.由于这里是将对象t整体使用的,所以t*m将调用对*的重载函数
    62        //即实际调用的函数为 t.operator*(m)
    63    }
    64 07)总结:
    65    如果在类声明中即声明了对*的重载函数Time operator*(double d) const;
    66    在类声明在又声明了友元函数:friend Time operator*(doubla m,const Time & t);
    67    该友元函数同时对*运算符进行了重载,那么在主函数中就可以使用下面的两种方式
    68    s1 = s2 * 2.1;  //调用对*的重载函数,编译器将其转换为s1 = s2.operator(2.1);
    69    s1 = 2.1 * s2;  //调用友元函数,编译器将其转换为:s1 = operator(2.1,s2);
    70    即实现了乘法的交换律。
    71 */
    mytime.h
      1 //mytime.cpp
      2 //使用运算符重载版本
      3 //用 Time operater+(Time & s) const 代替Time Sum(Time & T);即可
      4 //重载-运算符Time Time::operator-(const Time & T) const 
      5 //重载*运算符Time Time::operator*(double d) const
      6 #include <iostream>
      7 #include "mytime.h"
      8 
      9 Time::Time()  //默认构造函数的定义,创建类对象时,默认执行以下操作
     10 {
     11     hour = 0;
     12     minitue = 0;
     13 }
     14 
     15 
     16 /*Time::Time(int & h, int & m) *///构造函数定义,创建类对象时,使用构造函数时执行以下操作.
     17 //声明构造函数,如果是这样声明构造函数的话,在主函数中调用构造函数,传入一个数字是不合法的
     18 //即 int & h = 4;  这样是不合法的
     19 Time::Time(int  h, int  m)  //这样在声明类对象的时候,调用该构造函数才是合法的,因为将数字传递给引用是不合法的
     20 {
     21     hour = h;
     22     minitue = m;
     23 }
     24 
     25 Time Time::operator+(const Time & T) const
     26 {
     27     Time s;  //新建一个TIme对象,用于作为该函数的返回值
     28     s.minitue = minitue + T.minitue;
     29     s.hour = hour + T.hour + s.minitue / 60; 
     30     //hour是调用Sum()方法的对象中的数据,T.hour是作为实参传入的对象中的数据
     31     //最后再加上调用对象的分钟数,和,作为实参传入的分钟数的和,然后取整
     32     s.minitue = s.minitue % 60;  //对两个对象中数据的分钟数取余
     33 
     34     return s;
     35 }
     36 //注意:Sum()函数的返回值不能是Time & (指向Time对象的引用),这是由于返回的对象时s,而s是一个在Sum()
     37 //中定义的局部变量,Sum()函数执行完毕后,s将会消失,返回一个消失的引用是不合适的
     38 //所以这里返回s对象的副本,之后在主函数中可以使用它 
     39 //以前函数的返回值可以为引用,是因为返回的对象均为从主函数中传入的对象,这些对象都是在主函数中定义的
     40 //所以可以返回,比如this指针那里,传入一个对象和this指针指向的调用类方法的对象
     41 
     42 //对-运算符进行重载
     43 Time Time::operator-(const Time & T) const 
     44 {
     45     Time s;  //创建一个局部对象,作为返回值
     46     s.minitue = minitue - T.minitue;  
     47     s.hour = hour - T.hour + s.minitue/60; //虽然是减,但是为了以防万一,还是加上这个取整吧
     48     s.minitue = s.minitue % 60;
     49 
     50     return s;
     51 }
     52 
     53 //对*运算符进行重载
     54 Time Time::operator*(double d) const
     55 {
     56     Time s;  //创建一个局部对象,作为返回值
     57     long total_time = hour * 60 * d + minitue * d;//这种都hour和minitue都相乘的方法是从书中学到的
     58     s.hour = total_time / 60;
     59     s.minitue = total_time % 60;  
     60 
     61     return s;
     62 }
     63 
     64 //只是增加小时
     65 void Time::Addhour(int h)
     66 {
     67     hour = hour + h;
     68 }
     69 
     70 //只是增加分钟
     71 void Time::Addminitue(int m)
     72 {
     73     minitue = minitue + m;
     74     hour = hour + minitue / 60;  //如果增加的分钟数超过了60则对minitue以60为底取整
     75     minitue = minitue % 60;  //如果增加的分钟数超过了60则对minitue以60为底取余
     76 }
     77 
     78 //重置时间
     79 void Time::Reset(int h, int m)
     80 {
     81     hour = h;
     82     minitue = m;
     83 }
     84 
     85 //友元函数的定义
     86 //由于友元函数不是类成员函数,所以不能使用Time::限定符
     87 //在友元函数的定义中也不能出现关键字friend
     88 //但是友元函数却可以访问Time类中的私有数据和公有数据
     89 Time operator*(double m, const Time & t)
     90 {
     91     Time result;
     92     long total_time = t.hour * 60 * m + t.minitue * m;
     93     result.hour = total_time / 60;
     94     result.minitue = total_time % 60;
     95 
     96     return result;
     97 }
     98 
     99 //显示对象中的数据
    100 void Time::show()
    101 {
    102     std::cout << "hour= " << hour << " minitue= " << minitue << std::endl;
    103 }
    mytime.cpp
     1 //user_main.cpp
     2 //使用运算符重载版本
     3 //用s1=s2+s3代替s1 = s2.Sum(s3);即可
     4 //s1=s2+s3;实际上是调用函数的方法:s1=s2.operator+(s3);
     5 #include <iostream>
     6 #include "mytime.h"
     7 
     8 int main()
     9 {
    10     Time s1;  //定义一个Time类对象,并用默认构造函数进行初始化
    11     Time s2(2, 40);  //定义一个Time类对象,并隐式的调用构造函数
    12     Time s3(5, 55);  //定义一个Time类对象,并隐式的调用构造函数
    13 
    14     std::cout << "使用*运算符重载方法:" << std::endl;
    15     s1 = s2 * 2;   //等价于s1 = s1.operator*(2);
    16     s1.show();
    17 
    18     s2.Reset(2,40);  //对象s2调用类方法Reset(),并使用实参覆盖掉默认参数
    19 
    20     std::cout << "使用友元函数:" << std::endl;
    21     s1 = 2 * s2;   //等价于s1 = operator*(2,s2);
    22     s1.show();
    23 
    24 
    25     system("pause");
    26     return 0;
    27 }
    usre_main.cpp

    执行结果为:

    对<<运算符的重载&友元函数 

    01)问题的提出:
       在以前的程序版本中,加入要为显示一个Time对象trip的值,我们都是用的一个类方法show(),对象调用类方法
       的方式为trip.show()。能不能用cout<<trip;呢,答案是可以的,因为<<也是C++运算符之一
    02)运算符<<的历史和cout对象的相关介绍
       最初<<运算符是c和c++位运算符,将值中的位左移。ostream类对该运算符进行了重载,将其转换为一个输出工具。
       而cout又是类ostream的一个对象,能够识别C++基本类型。这是因为对于每种C++基本类型,ostream类声明中
       都包含了相应的重载operator<<()定义。也就是说,一个定义使用int型参数,一个定义使用double型参数,一个定义
       使用char型参数等等。因此要让cout能够识别TIme对象,一种方法是将一个新的函数运算符定义添加到ostream
       类声明中,但修改ostream类是一个坏主意;一种方法是让Time知道任何使用cout,即在Time中声明对<<的重载函数
    03)那么在Time类中声明友元函数还是非友元函数?
       如果是声明常规的类方法,则在<<运算符的左边一定是一个Time对象,那么输出就是下面的那样了:
       trip<<cout; //这样显然是不合适的
       所以要使用友元函数:
       void operator<<(ostream & os, const Time & t) //其中ostream是一个类
       {
       os << t.hour <<" hours" << t.minitue <<"minitues ";
       }
       这样就可以使用下面的语句了:
       cout<<trip; //显示对象trip中的数据了
       调用cout<<trip应使用cout对象本身,而不是cout的副本,因此应该使用ostream & os以用,而不是按值传递
       Time对象可以按值传递或者是按引用传递,按引用传递比按值传递使用的时间和内存都要少,因此使用按引用传递。
    04)改进
      很显然,上面对<<重载友元函数对于下面这样的语句是无能为力的:
       cout<<"Trip time: "<<trip<<"(Tuesday) ";
    05)解决方法让cout<<"Trip time: "返回一个cout即可解决问题。反应在对<<重载友元函数来说就是返回值为
       指向ostream对象的引用即可,即下面改进的对<<重载友元函数版本:
      ostream & operator<<(ostream & os, const Time & t) //其中ostream是一个类
      {
        os << t.hour <<" hours" << t.minitue <<"minitues ";
        return os;
      }
       注意:返回值不再是void了,而是指向ostream对象的引用
    06)上面的这个operator<<()函数版本还可以用于将输出写如到文件中:
      #include <fstream> //for ofstream
      ...
      ofstream fout; //创建一个ofstream类对象fout
      fout.open("savetime.txt"); //对象fout和一个txt文件关联
      Time trip(12,40); //创建一个Time类对象trip,并隐式的调用构造函数初始化trip对象
      fout<<trip; //实际调用方式为 operator<<(fout,trip);

      1 //mytime.h
      2 //包含了operator*()和operatro<<()两个友元函数
      3 //将operator*()作为内联函数,因为其代码很短(定义也是原型时,要使用关键字friend)
      4 
      5 #ifndef MYTIME_H_
      6 #define MYTIME_H_
      7 #include <iostream>  //这里声明了,在mytime.cpp就只包含mytime.h头文件,便可以提供iostream头文件的支持
      8 
      9 class Time
     10 {
     11 private:
     12     int hour; 
     13     int minitue;
     14 public:
     15     Time();  //声明默认构造函数
     16     Time(int  h, int  m);  //声明构造函数
     17     Time operator+(const Time & T) const;  
     18     Time operator-(const Time & T) const; //两个const可有可无
     19     Time operator*(double d) const;  //最后一个const还是表明不能修改调用operator*()方法的对象中的数据
     20     friend Time operator*(double m, const Time & t)  //即使原型是定义,要使用关键字friend,同时也是内联函数
     21     {
     22         return t * m;  //实际上调用方法为t.operator*(m),即调用对*的重载函数
     23     }
     24     friend std::ostream & operator<<(std::ostream & os, Time & t);//声明一个对运算符<<重载的友元函数
     25     void Addhour(int h);  //单独的增加小时
     26     void Addminitue(int m);  //单独的增加分钟
     27     void Reset(int h=0, int m=0);  //重置时间
     28     void show();
     29 };
     30 
     31 #endif
     32 
     33 
     34 /* 友元函数 */
     35 /*
     36 01)问题的提出:
     37    对于上一个代码中的对*的函数重载中 Time operator*(double d) const;
     38    对Time对象s1和s2,以及一个double值2.1
     39    使用方法只能是s1 = s2*2.1;//实际上是调用对*的重载函数:s1=s2.operator(2.1);
     40    所以s1 = 2.1*s2; 是会报错的
     41 02)解决方法:
     42    A 写注释:告诉每个人只能按照s2*2.1这种方式去写,不能写成2.1*s2
     43    B 使用非成员函数,非成员函数不是由对象调用的,它使用的值都必须是由实参的形式传入的
     44      但是也引发了一个新问题:非成员函数不能访问私有数据。最终的解决方法是使用友元函数
     45 03)友元函数的声明方法:使用关键字friend
     46    friend Time operator*(doubla m,const Time & t);//该友元函数同时对*运算符进行了重载
     47    该声明意味着下面两点:
     48    A 虽然operator*()是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用;
     49    B 虽然operatir*()不是成员函数,但它有成员函数的访问权限。(可以访问私有数据)
     50 04)友元函数的定义方法:不用使用关键字friend,因为它不是成员函数,所以也不用使用Time::限定符
     51    Time operator*(double m, Time & t) const
     52    {
     53        Time result;
     54        long total_time = t.hour * m + t.minitue * m;
     55        result.hour = total_time / 60;
     56        result.minitue = total_time % 60;
     57        return result;
     58    }
     59 05)友元函数调用方法:
     60    有了友元函数之后,就可以直接使用 s1 = 2.1*s2;
     61    编译器将s1 = 2.1*s2;转换成s1 = operator*(2.1,s2);友元函数版本
     62 06)稍作修改,就可以将友元函数改变成非友元函数:
     63    //在该非友元函数中调用对*的重载函数
     64    Time operator*(double m, Time & t) const  
     65    {
     66        return t*m; 
     67        //原来的版本是显式的访问t.hour和t.minitue.由于这里是将对象t整体使用的,所以t*m将调用对*的重载函数
     68        //即实际调用的函数为 t.operator*(m)
     69    }
     70 07)总结:
     71    如果在类声明中即声明了对*的重载函数Time operator*(double d) const;
     72    在类声明在又声明了友元函数:friend Time operator*(doubla m,const Time & t);
     73    该友元函数同时对*运算符进行了重载,那么在主函数中就可以使用下面的两种方式
     74    s1 = s2 * 2.1;  //调用对*的重载函数,编译器将其转换为s1 = s2.operator(2.1);
     75    s1 = 2.1 * s2;  //调用友元函数,编译器将其转换为:s1 = operator(2.1,s2);
     76    即实现了乘法的交换律。
     77 */
     78 
     79 /* 对<<运算符的重载&友元函数 */
     80 /*
     81 01)问题的提出:
     82    在以前的程序版本中,加入要为显示一个Time对象trip的值,我们都是用的一个类方法show(),对象调用类方法
     83    的方式为trip.show()。能不能用cout<<trip;呢,答案是可以的,因为<<也是C++运算符之一
     84 02)运算符<<的历史和cout对象的相关介绍
     85    最初<<运算符是c和c++位运算符,将值中的位左移。ostream类对该运算符进行了重载,将其转换为一个输出工具。
     86    而cout又是类ostream的一个对象,能够识别C++基本类型。这是因为对于每种C++基本类型,ostream类声明中
     87    都包含了相应的重载operator<<()定义。也就是说,一个定义使用int型参数,一个定义使用double型参数,一个定义
     88    使用char型参数等等。因此要让cout能够识别TIme对象,一种方法是将一个新的函数运算符定义添加到ostream
     89    类声明中,但修改ostream类是一个坏主意;一种方法是让Time知道任何使用cout,即在Time中声明对<<的重载函数
     90 03)那么在Time类中声明友元函数还是非友元函数?
     91    如果是声明常规的类方法,则在<<运算符的左边一定是一个Time对象,那么输出就是下面的那样了:
     92    trip<<cout;  //这样显然是不合适的
     93    所以要使用友元函数:
     94    void operator<<(ostream & os, const Time & t) //其中ostream是一个类
     95    {
     96      os << t.hour <<" hours" << t.minitue <<"minitues
    ";
     97    }
     98    这样就可以使用下面的语句了:
     99    cout<<trip;  //显示对象trip中的数据了
    100    调用cout<<trip应使用cout对象本身,而不是cout的副本,因此应该使用ostream & os以用,而不是按值传递
    101    Time对象可以按值传递或者是按引用传递,按引用传递比按值传递使用的时间和内存都要少,因此使用按引用传递。
    102 04)改进
    103    很显然,上面对<<重载友元函数对于下面这样的语句是无能为力的:
    104    cout<<"Trip time: "<<trip<<"(Tuesday)
    ";
    105 05)解决方法:让cout<<"Trip time: "返回一个cout即可解决问题。反应在对<<重载友元函数来说就是返回值为
    106    指向ostream对象的引用即可,即下面改进的对<<重载友元函数版本:
    107    ostream & operator<<(ostream & os, const Time & t) //其中ostream是一个类
    108    {
    109      os << t.hour <<" hours" << t.minitue <<"minitues
    ";
    110      return os;
    111    }
    112    注意:返回值不再是void了,而是指向ostream对象的引用
    113 06)上面的这个operator<<()函数版本还可以用于将输出写如到文件中:
    114    #include <fstream> //for ofstream
    115    ...
    116    ofstream fout;  //创建一个ofstream类对象fout
    117    fout.open("savetime.txt");  //对象fout和一个txt文件关联
    118    Time trip(12,40);  //创建一个Time类对象trip,并隐式的调用构造函数初始化trip对象
    119    fout<<trip;  //实际调用方式为 operator<<(fout,trip);
    120 
    121 */
    mytime.h
      1 //mytime.cpp
      2 //使用运算符重载版本
      3 //用 Time operater+(Time & s) const 代替Time Sum(Time & T);即可
      4 //重载-运算符Time Time::operator-(const Time & T) const 
      5 //重载*运算符Time Time::operator*(double d) const
      6 //#include <iostream> //可以不包含该头文件了,因为在mytime.h头文件中引用了该头文件,且在本文件中包含了mytime.h头文件
      7 #include "mytime.h" 
      8 
      9 Time::Time()  //默认构造函数的定义,创建类对象时,默认执行以下操作
     10 {
     11     hour = 0;
     12     minitue = 0;
     13 }
     14 
     15 
     16 /*Time::Time(int & h, int & m) *///构造函数定义,创建类对象时,使用构造函数时执行以下操作.
     17 //声明构造函数,如果是这样声明构造函数的话,在主函数中调用构造函数,传入一个数字是不合法的
     18 //即 int & h = 4;  这样是不合法的
     19 Time::Time(int  h, int  m)  //这样在声明类对象的时候,调用该构造函数才是合法的,因为将数字传递给引用是不合法的
     20 {
     21     hour = h;
     22     minitue = m;
     23 }
     24 
     25 Time Time::operator+(const Time & T) const
     26 {
     27     Time s;  //新建一个TIme对象,用于作为该函数的返回值
     28     s.minitue = minitue + T.minitue;
     29     s.hour = hour + T.hour + s.minitue / 60;
     30     //hour是调用Sum()方法的对象中的数据,T.hour是作为实参传入的对象中的数据
     31     //最后再加上调用对象的分钟数,和,作为实参传入的分钟数的和,然后取整
     32     s.minitue = s.minitue % 60;  //对两个对象中数据的分钟数取余
     33 
     34     return s;
     35 }
     36 
     37 //对-运算符进行重载
     38 Time Time::operator-(const Time & T) const 
     39 {
     40     Time s;  //创建一个局部对象,作为返回值
     41     s.minitue = minitue - T.minitue;  
     42     s.hour = hour - T.hour + s.minitue/60; //虽然是减,但是为了以防万一,还是加上这个取整吧
     43     s.minitue = s.minitue % 60;
     44 
     45     return s;
     46 }
     47 
     48 //对*运算符进行重载
     49 Time Time::operator*(double d) const
     50 {
     51     Time s;  //创建一个局部对象,作为返回值
     52     long total_time = hour * 60 * d + minitue * d;//这种都hour和minitue都相乘的方法是从书中学到的
     53     s.hour = total_time / 60;
     54     s.minitue = total_time % 60;  
     55 
     56     return s;
     57 }
     58 
     59 //只是增加小时,常规类方法
     60 void Time::Addhour(int h)
     61 {
     62     hour = hour + h;
     63 }
     64 
     65 //只是增加分钟,常规类方法
     66 void Time::Addminitue(int m)
     67 {
     68     minitue = minitue + m;
     69     hour = hour + minitue / 60;  //如果增加的分钟数超过了60则对minitue以60为底取整
     70     minitue = minitue % 60;  //如果增加的分钟数超过了60则对minitue以60为底取余
     71 }
     72 
     73 //重置时间,常规类方法
     74 void Time::Reset(int h, int m)
     75 {
     76     hour = h;
     77     minitue = m;
     78 }
     79 
     80 //友元函数的定义
     81 //由于友元函数不是类成员函数,所以不能使用Time::限定符
     82 //在友元函数的定义中也不能出现关键字friend
     83 //但是友元函数却可以访问Time类中的私有数据和公有数据
     84 //Time operator*(double m, const Time & t)  //该函数已经在头文件中声明和定义
     85 //{
     86 //    Time result;
     87 //    long total_time = t.hour * 60 * m + t.minitue * m;
     88 //    result.hour = total_time / 60;
     89 //    result.minitue = total_time % 60;
     90 //
     91 //    return result;
     92 //}
     93 
     94 //cout<<trip实现
     95 //对<<运算符进行重载的友元函数定义
     96 //由于ostream在名称空间std中,所以要使用std::限定符
     97 //对于os,将被从主函数传入的实参代替,由于该实参是在转函数中产生,所以operator<<()函数执行完毕后
     98 //该实参也存在,所以返回值的类型可以是引用
     99 //如果是在一个子函数中创建的局部变量,则返回类型就不能是引用了
    100 std::ostream & operator<<(std::ostream & os, Time & t)
    101 {
    102     os << t.hour << " hours" << t.minitue << " minitues
    ";
    103     return os;  
    104 }
    105 
    106 //显示对象中的数据
    107 void Time::show()
    108 {
    109     std::cout << "hour= " << hour << " minitue= " << minitue << std::endl;
    110 }
    mytime.cpp
     1 //user_main.cpp
     2 //使用运算符重载版本
     3 //用s1=s2+s3代替s1 = s2.Sum(s3);即可
     4 //s1=s2+s3;实际上是调用函数的方法:s1=s2.operator+(s3);
     5 #include <iostream>
     6 #include "mytime.h"
     7 
     8 int main()
     9 {
    10     using std::cout;
    11     using std::endl;
    12 
    13     Time s1;  //定义一个Time类对象,并用默认构造函数进行初始化
    14     Time s2(2, 40);  //定义一个Time类对象,并隐式的调用构造函数
    15     Time s3(5, 55);  //定义一个Time类对象,并隐式的调用构造函数
    16 
    17     std::cout << "使用*运算符重载方法:" << std::endl;
    18     s1 = s2 * 2;   //等价于s1 = s1.operator*(2);
    19     cout << s1;  //和使用s1.show()的作用是一样的
    20 
    21     s2.Reset(2,40);  //对象s2调用类方法Reset(),并使用实参覆盖掉默认参数
    22 
    23     std::cout << "使用友元函数:" << std::endl;
    24     s1 = 2 * s2;   //等价于s1 = operator*(2,s2);
    25     cout << s1;  //和使用s1.show()的作用是一样的
    26      
    27 
    28     system("pause");
    29     return 0;
    30 }
    user_main.cpp

    执行结果为:

     cin.clear()的用法 m5

    我们谈谈cin.clear的作用,第一次看到这东西,很多人以为就是清空cin里面的数据流,而实际上却与此相差很远,首先我们看看以下代码:

    #include <iostream> 
    using namespace std; 
    int main()  
    {         
        int a;         
        cin>>a;         
        cout<<cin.rdstate()<<endl;         
        if(cin.rdstate() == ios::goodbit)   
        {   
            cout<<"输入数据的类型正确,无错误!"<<endl;               
        }         
        if(cin.rdstate() == ios_base::failbit)         
        {                 
            cout<<"输入数据类型错误,非致命错误,可清除输入缓冲区挽回!"<<endl;         
        }         
        system("pause"); 
    }
     
    我们定义要输入到的变量是整型,但如果我们输入了英文字母或者汉字,那就会发生错误,cin里有个方法能检测这个错误,就是cin.rdstate(); 当cin.rdstate()返回0(即ios::goodbit)时表示无错误,可以继续输入或者操作,若返回4则发生非致命错误即ios::failbit,则不能继续输入或操作.而cin.clear则可以控制我们此时cin里对这个问题的一个标识.语发如下: cin.clear(标识符); 标识符号为:

    goodbit 无错误 
    Eofbit 已到达文件尾 
    failbit 非致命的输入/输出错误,可挽回 
    badbit 致命的输入/输出错误,无法挽回 若在输入输出类里.需要加ios::标识符号 
    通过cin.clear,我们能确认它的内部标识符,如果输入错误则能重新输入.结合真正的清空数据流方法cin.sync(),请看下例:
    #include <iostream> 
    using namespace std; 
    int main()  
    {         
        int a;         
        while(1)         
        {                 
            cin>>a;                 
            if(!cin)            //条件可改写为cin.fail()                 
            {                         
                cout<<"输入有错!请重新输入"<<endl;                         
                cin.clear();                          
                cin.sync();   //清空流                 
            }                 
            else                 
            {                         
                cout<<a;                         
                break;                 
            }         
        }         
        system("pause"); 
    }
    上面的cin.clear()默认参数为0,即无错误,正常操作.当我们输入英文字母'k'时,它的状态标识改为fail,即错误,用cout对用户输出信息,再用cin.clear让错误标识改回为0,让我们可以继续输入,再清空流数据继续输入.如果我们没有了cin.clear,则会进入死循环,其过程为我们输入了英文字母,它的状态标识便为fail,当运行到条件判断时,便总是回到错误的条件表示里,并且我们再也没办法输入,因为错误的表示关闭了cin,所以会进入死循环.

    极坐标和直角坐标的相互转换(随机漫步的实现) 

    /* 总结 */
    01)对象是不可以直接调用类中的私有变量的,只能调用公有函数!!
         所以加入对象result要使用x值怎么办?result.x是不合法的,所以使用result.xval();
    02)使用了名称空间来创建类,或在名称空间中创建类,那么类中的方法定义的时候,一种方法是和h文件中写的一样:使用
         namespace VECT{ ... }; 另一种方法就是在cpp文件中使用using声明
    03)如果使用using声明,那么定义友元函数的时候,在友元函数名之前是要加上名称空间的名字+双冒号的,否则友元函数
         不能访问类中的私有数据

     1 //vect.h
     2 //极坐标和直角坐标的相互转换
     3 
     4 #ifndef VECTOR_H_
     5 #define VECTOR_H_
     6 
     7 //定义一个名称空间VECTOR,将类定义放在名称空间中
     8 namespace VECTOR  
     9 {
    10     class Vector
    11     {
    12     public:
    13         enum Mode {RECT,POL}; //定义枚举量Mode,可以用Mode去定义变量,例如Mode M; 但是只能用RECT和POL对M赋值
    14     private:
    15         double x; //直角坐标系的横坐标
    16         double y; //直角坐标系的纵坐标
    17         double mag;  //极坐标系的长度
    18         double ang;  //极坐标系的角度
    19         Mode mode;  //用枚举量定义一个枚举变量,mode的值只能是RECT或POL
    20         void set_mag();  //设置极坐标系的长度函数
    21         void set_ang();  //设置极坐标系的角度函数
    22         void set_x();
    23         void set_y();  
    24     public:
    25         Vector();  //默认构造函数的声明
    26         ~Vector();  //析构函数的声明
    27     //声明构造函数,n1和n2是传入的直角坐标系或者是极坐标系的坐标,默认是RECT(直角坐标系模式)
    28         Vector(double n1, double n2, Mode form = RECT); 
    29     //声明重置函数,作用类似于析构函数,只不过reset()可以随时使用,而是构函数只有在类创建对象的时候才会被使用
    30         void reset(double n1, double n2, Mode form = RECT);
    31     //定义返回x、y、mag、ang的值的函数,由于是在类中定义,自动成为内联函数
    32     //const放在了函数名括号的后面,表示该函数不可以修改调用该函数对象的参数
    33     //对象是不可以直接调用类中的私有变量的,只能调用公有函数!!
    34     //所以加入对象result要使用x值怎么办?result.x是不合法的,所以使用result.xval();
    35         double xval() const { return x; }  
    36         double yval() const { return y; }
    37         double magval() const { return mag; }
    38         double angval() const { return ang; }
    39     //直角坐标系或者是极坐标系模式的选择
    40         void polar_mode();
    41         void rect_mode();
    42     //运算符重载
    43         Vector operator+(const Vector & b) const;  //第一个Vector表示operator+()函数的返回值为Vector类对象
    44         Vector operator-(const Vector & b) const;
    45         Vector operator-() const;  //对类对象中的数据进行去反操作,即正负的变换
    46         Vector operator*(double n) const;
    47     //友元函数的声明
    48         friend Vector operator*(double n,const Vector & b);
    49         friend std::ostream & operator<<(std::ostream & os, const Vector & v);
    50     };
    51 }
    52 
    53 #endif
    54 
    55 /* 总结 */
    56 /*
    57 01)对象是不可以直接调用类中的私有变量的,只能调用公有函数!!
    58    所以加入对象result要使用x值怎么办?result.x是不合法的,所以使用result.xval();
    59 02)使用了名称空间来创建类,或在名称空间中创建类,那么类中的方法定义的时候,一种方法是和h文件中写的一样:使用
    60    namespace VECT{ ... }; 另一种方法就是在cpp文件中使用using声明
    61 03)如果使用using声明,那么定义友元函数的时候,在友元函数名之前是要加上名称空间的名字+双冒号的,否则友元函数
    62    不能访问类中的私有数据
    63 */
    vect.h
      1 //vector.cpp
      2 #include <iostream>
      3 #include <cmath>  //for sqrt()、sin()、cos()、atan()、atan()、
      4 #include "vect.h"
      5 
      6 
      7 using VECTOR::Vector;  //声明名称空间中的类,以后就可以直接使用类中的方法
      8 using std::sqrt;  //开根号
      9 using std::sin;
     10 using std::cos;
     11 using std::atan;  //atan(x)表示求x的反正切,返回值为[-pi/2,pi/2]区间的一个值,返回弧度值
     12 using std::atan2;  //atan2(y,x)表示求y/x的正切,返回值为[-pi,pi]区间的一个值,y是纵坐标的值
     13 using std::cout;
     14 using std::endl;
     15 
     16 //输入的是度数,而程序中要用弧度值,所以需要180/pi,例如将60°转换为弧度值方法为60/rad_to_deg
     17 const double rad_to_deg = 180.0 / 3.14;  
     18 
     19 //默认构造函数定义
     20 Vector::Vector()
     21 {
     22     x = y = mag = ang = 0;
     23     mode = RECT;  //刚刚这一句丢了
     24 }
     25 
     26 //析构函数定义
     27 Vector::~Vector()
     28 {
     29 
     30 }
     31 
     32 //构造函数定义
     33 Vector::Vector(double n1, double n2, Mode form)
     34 {
     35     mode = form;
     36     if (form == RECT)
     37     {
     38         x = n1;    //将传入的直角坐标系的参数传递给类中的成员变量x和y
     39         y = n2;
     40         set_mag(); //设置x和y对应的极坐标系中的值
     41         set_ang();
     42     }
     43     else if (form == POL)
     44     {
     45         mag = n1;
     46         ang = n2 / rad_to_deg;  //将度数转换为弧度制
     47         set_x();
     48         set_y();
     49     }
     50     else
     51     {
     52         cout << "您输入有误,将坐标系的值全部设置为0" << endl;
     53         x = y = mag = ang = 0;
     54     }
     55         
     56 }
     57 
     58 //重置函数的定义  这个方法不能用
     59 //void Vector::reset(double n1, double n2, Mode f)
     60 //{
     61 //    Vector(n1, n2, f);  //调用构造函数
     62 //}
     63 void Vector::reset(double n1, double n2, Mode form)
     64 {
     65     mode = form;
     66     if (form == RECT)
     67     {
     68         x = n1;    //将传入的直角坐标系的参数传递给类中的成员变量x和y
     69         y = n2;
     70         set_mag(); //设置x和y对应的极坐标系中的值
     71         set_ang();
     72     }
     73     else if (form == POL)
     74     {
     75         mag = n1;
     76         ang = n2 / rad_to_deg;  //将度数转换为弧度制
     77         set_x();
     78         set_y();
     79     }
     80     else
     81     {
     82         cout << "您输入有误,将坐标系的值全部设置为0" << endl;
     83         x = y = mag = ang = 0;
     84     }
     85 }
     86 
     87 //设置极坐标系的长度函数
     88 void Vector::set_mag()
     89 {
     90     mag = sqrt(x * x + y * y);
     91 }
     92 void Vector::set_ang()
     93 {
     94     ang = atan2(y, x);  //返回(x,y)的正切值
     95 }
     96 void Vector::set_x()
     97 {
     98     x = mag * cos(ang);
     99 }
    100 void Vector::set_y()
    101 {
    102     y = mag * sin(ang);
    103 }
    104 
    105 //直角坐标系或者是极坐标系模式的选择
    106 void Vector::polar_mode()
    107 {
    108     mode = POL;
    109 }
    110 void Vector::rect_mode()
    111 {
    112     mode = RECT;
    113 }
    114 
    115 //运算符重载
    116 Vector Vector::operator+(const Vector & b) const
    117 {
    118     //Vector V;  //新建一个类对象,作为返回值
    119     //V.x = x + b.x;  //自己的想法
    120 
    121     return Vector(x + b.x, y + b.y);  //调用构造函数,模式选择为默认值RECT
    122     //不用去别另外的一个模式,因为在主函数中即使是用RECT模式去减
    123     //接下来,RECT模式也会转换为POL模式中的参数的
    124     //x和y的值为调用operator+()对象中的数据,b.x为作为实参传入的对象中的数据
    125     
    126 }
    127 Vector Vector::operator-(const Vector & b) const
    128 {
    129     return Vector(x - b.x, y - b.y); //调用构造函数,模式选择为默认值RECT
    130     //x和y的值为调用operator-()对象中的数据,b.x为作为实参传入的对象中的数据
    131 }
    132 Vector Vector::operator-() const
    133 {
    134     return Vector(-x, -y);
    135     //x和y的值为调用operator-()对象中的数据
    136 }
    137 Vector Vector::operator*(double n) const
    138 {
    139     return Vector(x*n, y*n);
    140     //x和y的值为调用operator-()对象中的数据
    141 }
    142 
    143 //友元函数的声明
    144 //Vector operator*(double n, const Vector & b) //刚刚没有使用名称空间对operator*()声明,导致b.x出错
    145 //如果友元函数在名称空间中,必须要使用名称空间对友元函数的函数名进行声明,否则无法访问类中的数据
    146 //还有一个方法是在cpp文件中也将namespace VECTOR{...},按照h文件中的写法,照样搬过来就可以不用加VECTOR::
    147 Vector VECTOR::operator*(double n, const Vector & b)
    148 {
    149     return Vector(b.x * n , b.y * n);
    150     //return b * n;
    151 }
    152 std::ostream & VECTOR::operator<<(std::ostream & os, const Vector & v)
    153 {
    154     if (v.mode == Vector::RECT)
    155         os << "(x,y) = " << "(" << v.x << "," << v.y << ")
    ";
    156     else if (v.mode == Vector::POL)
    157         os << "(mag,ang) = " << "(" << v.mag << "," << v.ang * rad_to_deg << ")
    ";  //将rad转换为度数
    158     else
    159         os << "Vector object mode is invalid
    ";
    160     return os;
    161 }
    vect.cpp
     1 #include <iostream>
     2 #include <ctime>  //for time()
     3 #include <cstdlib> //for rand()、srand()
     4 #include"vect.h"
     5 
     6 int main()
     7 {
     8     using namespace std;
     9     using VECTOR::Vector;
    10 
    11     srand(time(0));
    12 
    13     Vector step;  //使用默认构造函数创建对象,该对象中的数据全部为0,默认为直角坐标系
    14     Vector result(0.0, 0.0);  //隐式的调用构造函数创建对象,并将该对象中的变量设置为0,默认为直角坐标系
    15     double direction = 0.0;  //走的方向
    16     double dstep = 0.0;  //每步走的长度
    17     double target = 0.0;  //要走的长度,该长度为极坐标系中的长度
    18     unsigned long steps = 0.0;  //定义走的总步数
    19 
    20     cout << "Enter target distance(任意子母键退出): ";
    21     while (cin >> target)
    22     {
    23         cout << "Enter step length: ";
    24         if (!(cin >> dstep))
    25         {
    26             break;  //如果输入的不是数字,那么退出while循环
    27         }
    28         //对象时不可以直接调用类中的私有变量的,只能调用公有函数!!
    29         while (result.magval() < target)
    30         {
    31             direction = rand() % 360;  //防止随机数大于360出现的情况
    32             step.reset(dstep, direction, Vector::POL); //重置step对象在的数据
    33             result = result + step;
    34             /*steps++;*/  //走的总步数
    35             cout << steps++ << endl;
    36             cout << result.magval() << endl;
    37         }
    38         cout << "After " << steps << " steps, 对象到达了如下坐标(直角坐标系):";
    39         cout << result << endl;  //输出对象result中的数据,默认result对象的模式为RECT(直角坐标系)
    40         result.polar_mode();  //设置result对象的模式为极坐标系POL
    41         cout << "或者在极坐标系下的坐标为:" << endl;
    42         cout << result << endl;  //极坐标系下输出
    43 
    44         cout << "平均每步走的距离为:" << result.magval() / steps << endl;
    45 
    46         //重置变量,为下一次循环做准备
    47         steps = 0;
    48         result.reset(0.0, 0.0);
    49         cout << "Enter target distance(任意子母键退出): ";
    50     }
    51 
    52     cout << "Bye!
    ";
    53     cin.clear();  
    54     while (cin.get() != '
    ')
    55         continue;
    56     system("pause");
    57     return 0;
    58 }
    user_main.cpp

    ---恢复内容结束---

    目录

    用类方法合并另个时间&运算符重载(涉及到函数返回值能不能是引用的问题)

    用类方法合并另个时间的代码如下:

     1 //mytime.h
     2 #ifndef MYTIME_H_
     3 #define MYTIME_H_
     4 
     5 class Time
     6 {
     7 private:
     8     int hour;
     9     int minitue;
    10 public:
    11     Time();  //声明默认构造函数
    12     //Time(int & h, int & m);  //声明构造函数,如果是这样声明构造函数的话,在主函数中调用构造函数,传入一个数字是不合法的
    13     Time(int  h, int  m);  //声明构造函数
    14     Time Sum(Time & T);  //声明返回值为类对象的函数,形参为指向类对象的引用
    15     void Addhour(int h);  //单独的增加小时
    16     void Addminitue(int m);  //单独的增加分钟
    17     void Reset(int h=0, int m=0);  //重置时间
    18     void show();
    19 };
    20 
    21 #endif
    mytime.h
     1 //mytime.cpp
     2 #include <iostream>
     3 #include "mytime.h"
     4 
     5 Time::Time()  //默认构造函数的定义,创建类对象时,默认执行以下操作
     6 {
     7     hour = 0;
     8     minitue = 0;
     9 }
    10 
    11 
    12 /*Time::Time(int & h, int & m) *///构造函数定义,创建类对象时,使用构造函数时执行以下操作.
    13 //声明构造函数,如果是这样声明构造函数的话,在主函数中调用构造函数,传入一个数字是不合法的
    14 //即 int & h = 4;  这样是不合法的
    15 Time::Time(int  h, int  m)  //这样在声明类对象的时候,调用该构造函数才是合法的,因为将数字传递给引用是不合法的
    16 {
    17     hour = h;
    18     minitue = m;
    19 }
    20 
    21 Time Time::Sum(Time & T)
    22 {
    23     Time s;  //新建一个TIme对象,用于作为该函数的返回值
    24     s.minitue = minitue + T.minitue;
    25     s.hour = hour + T.hour + s.minitue / 60; 
    26     //hour是调用Sum()方法的对象中的数据,T.hour是作为实参传入的对象中的数据
    27     //最后再加上调用对象的分钟数,和,作为实参传入的分钟数的和,然后取整
    28     s.minitue = s.minitue % 60;  //对两个对象中数据的分钟数取余
    29 
    30     return s;
    31 }
    32 //注意:Sum()函数的返回值不能是Time & (指向Time对象的引用),这是由于返回的对象时s,而s是一个在Sum()
    33 //中定义的局部变量,Sum()函数执行完毕后,s将会消失,返回一个消失的引用是不合适的
    34 //所以这里返回s对象的副本,之后在主函数中可以使用它 
    35 //以前函数的返回值可以为引用,是因为返回的对象均为从主函数中传入的对象,这些对象都是在主函数中定义的
    36 //所以可以返回,比如this指针那里,传入一个对象和this指针指向的调用类方法的对象
    37 
    38 //只是增加小时
    39 void Time::Addhour(int h)
    40 {
    41     hour = hour + h;
    42 }
    43 
    44 //只是增加分钟
    45 void Time::Addminitue(int m)
    46 {
    47     minitue = minitue + m;
    48     hour = hour + minitue / 60;  //如果增加的分钟数超过了60则对minitue以60为底取整
    49     minitue = minitue % 60;  //如果增加的分钟数超过了60则对minitue以60为底取余
    50 }
    51 
    52 //重置时间
    53 void Time::Reset(int h, int m)
    54 {
    55     hour = h;
    56     minitue = m;
    57 }
    58 
    59 //显示对象中的数据
    60 void Time::show()
    61 {
    62     std::cout << "hour= " << hour << " minitue= " << minitue << std::endl;
    63 }
    mytime.cpp
     1 //user_main.cpp
     2 #include <iostream>
     3 #include "mytime.h"
     4 
     5 int main()
     6 {
     7     Time s1;  //定义一个Time类对象,并用默认构造函数进行初始化
     8     Time s2(2, 40);  //定义一个Time类对象,并隐式的调用构造函数
     9     Time s3(5, 55);  //定义一个Time类对象,并隐式的调用构造函数
    10 
    11     s1 = s2.Sum(s3); //将Sum()中的this指向s2,s形参用实参s3代替
    12     s1.show();
    13 
    14     s1.Addhour(3);  //对s1对象中的数据,只是增加小时
    15     s1.show();
    16 
    17     system("pause");
    18     return 0;
    19 }
    20 /* 总结 */
    21 /*
    22 01)关于引用的使用方法:int & rt = 3; 这样使用是不合法的,要注意在函数参数传递的时候不要发生这样的错误
    23 02)关于函数返回值的问题:如果一个变量(包括对象)是在该函数内创建的,那么是不可以以引用的方式返回的
    24    因为引用返回的都是该变量本身,而该变量在对应的函数执行完毕之后就消失了,从而发生错误。
    25    但是如果变量(对象)是从主函数中传入的,并且返回的也是从主函数中传入的变量(对象),那么是可以以引用
    26    的方式返回的。
    27 03)
    28 */
    user_main.cpp

    /* 总结 */
    01)关于引用的使用方法:int & rt = 3; 这样使用是不合法的,要注意在函数参数传递的时候不要发生这样的错误
    02)关于函数返回值的问题:如果一个变量(包括对象)是在该函数内创建的,那么是不可以以引用的方式返回的
         因为引用返回的都是该变量本身,而该变量在对应的函数执行完毕之后就消失了,从而发生错误。
         但是如果变量(对象)是从主函数中传入的,并且返回的也是从主函数中传入的变量(对象),那么是可以以引用
         的方式返回的。

     执行结果:

    运算符重载 

    01)要使用重载运算符,必须使用被称为运算符函数的特殊函数形式:
       operaterop(argument-list)
       其中operater为关键字,op是要重载的运算符,argument-list为形参,相当于创建一个名字为operaterop的函数
       比如对+进行重载即:operater+(),该函数没有形参
       op必须是有效的C++运算符,不能是@,但可以是[],因为[]是数组索引运算符
    02)运算符重载实际上仍然是函数调用,只不过换了一种形式
       假如对+进行重载即:operater+(Time & s) 其中Time是一个类
       那么就可以说使用如下方式对两个对象进行相加:
       s1 = s2 + s3; //其中s1、s2、s3都是Time类对象
       编译器发现s1 s2 s3都是类对象,因此使用相应的运算符函数进行替换:
       s1 = s2.operater+(s3); //所以说运算符重载实际上也还是函数调用
    03)s1 = s2 + s3;该式隐式的使用s2(因为s2调用了类方法),显式的使用了类对象s3(因为s3作为参数传入)
       当然s1 = s3 + s2; 也是可以的,因为s2和s3都是类对象
       上句就相当于s1 = s3.operater+(s2);了,即s3调用方法,s2作为参数传入

    /*  时间的运算,引入了+运算符重载、-运算符重载和*运算符重载  */

     1 //mytime.h
     2 //使用运算符重载版本
     3 //用 Time operater+(Time & s) const 代替Time Sum(Time & T);即可
     4 #ifndef MYTIME_H_
     5 #define MYTIME_H_
     6 
     7 class Time
     8 {
     9 private:
    10     int hour; 
    11     int minitue;
    12 public:
    13     Time();  //声明默认构造函数
    14     Time(int  h, int  m);  //声明构造函数
    15     Time operator+(const Time & T) const;  //对运算符进行重载,形参为执行类对象的引用,返回值为Time对象,
    16     //const Time & T 表明方法operator+()也不能修改作为参数传入的对象中的数据
    17     //最后一个const表明operater+()方法不能修改调用这个方法的对象中的数据
    18     Time operator-(const Time & T) const; //两个const可有可无
    19     Time operator*(double d) const;  //最后一个const还是表明不能修改调用operator*()方法的对象中的数据
    20     void Addhour(int h);  //单独的增加小时
    21     void Addminitue(int m);  //单独的增加分钟
    22     void Reset(int h=0, int m=0);  //重置时间
    23     void show();
    24 };
    25 
    26 #endif
    27 
    28 /* 运算符重载 */
    29 /*
    30 01)要使用重载运算符,必须使用被称为运算符函数的特殊函数形式:
    31    operaterop(argument-list)  
    32    其中operater为关键字,op是要重载的运算符,argument-list为形参,相当于创建一个名字为operaterop的函数
    33    比如对+进行重载即:operater+(),该函数没有形参
    34    op必须是有效的C++运算符,不能是@,但可以是[],因为[]是数组索引运算符
    35 02)运算符重载实际上仍然是函数调用,只不过换了一种形式
    36    假如对+进行重载即:operater+(Time & s)  其中Time是一个类
    37    那么就可以说使用如下方式对两个对象进行相加:
    38    s1 = s2 + s3;  //其中s1、s2、s3都是Time类对象
    39    编译器发现s1 s2 s3都是类对象,因此使用相应的运算符函数进行替换:
    40    s1 = s2.operater+(s3);  //所以说运算符重载实际上也还是函数调用
    41 03)s1 = s2 + s3;该式隐式的使用s2(因为s2调用了类方法),显式的使用了类对象s3(因为s3作为参数传入)
    42    当然s1 = s3 + s2; 也是可以的,因为s2和s3都是类对象
    43    上句就相当于s1 = s3.operater+(s2);了,即s3调用方法,s2作为参数传入
    44 
    45 */
    mytime.h
     1 //mytime.cpp
     2 //使用运算符重载版本
     3 //用 Time operater+(Time & s) const 代替Time Sum(Time & T);即可
     4 //重载-运算符Time Time::operator-(const Time & T) const 
     5 //重载*运算符Time Time::operator*(double d) const
     6 #include <iostream>
     7 #include "mytime.h"
     8 
     9 Time::Time()  //默认构造函数的定义,创建类对象时,默认执行以下操作
    10 {
    11     hour = 0;
    12     minitue = 0;
    13 }
    14 
    15 
    16 /*Time::Time(int & h, int & m) *///构造函数定义,创建类对象时,使用构造函数时执行以下操作.
    17 //声明构造函数,如果是这样声明构造函数的话,在主函数中调用构造函数,传入一个数字是不合法的
    18 //即 int & h = 4;  这样是不合法的
    19 Time::Time(int  h, int  m)  //这样在声明类对象的时候,调用该构造函数才是合法的,因为将数字传递给引用是不合法的
    20 {
    21     hour = h;
    22     minitue = m;
    23 }
    24 
    25 Time Time::operator+(const Time & T) const
    26 {
    27     Time s;  //新建一个TIme对象,用于作为该函数的返回值
    28     s.minitue = minitue + T.minitue;
    29     s.hour = hour + T.hour + s.minitue / 60; 
    30     //hour是调用Sum()方法的对象中的数据,T.hour是作为实参传入的对象中的数据
    31     //最后再加上调用对象的分钟数,和,作为实参传入的分钟数的和,然后取整
    32     s.minitue = s.minitue % 60;  //对两个对象中数据的分钟数取余
    33 
    34     return s;
    35 }
    36 //注意:Sum()函数的返回值不能是Time & (指向Time对象的引用),这是由于返回的对象时s,而s是一个在Sum()
    37 //中定义的局部变量,Sum()函数执行完毕后,s将会消失,返回一个消失的引用是不合适的
    38 //所以这里返回s对象的副本,之后在主函数中可以使用它 
    39 //以前函数的返回值可以为引用,是因为返回的对象均为从主函数中传入的对象,这些对象都是在主函数中定义的
    40 //所以可以返回,比如this指针那里,传入一个对象和this指针指向的调用类方法的对象
    41 
    42 //对-运算符进行重载
    43 Time Time::operator-(const Time & T) const 
    44 {
    45     Time s;  //创建一个局部对象,作为返回值
    46     s.minitue = minitue - T.minitue;  
    47     s.hour = hour - T.hour + s.minitue/60; //虽然是减,但是为了以防万一,还是加上这个取整吧
    48     s.minitue = s.minitue % 60;
    49 
    50     return s;
    51 }
    52 
    53 //对*运算符进行重载
    54 Time Time::operator*(double d) const
    55 {
    56     Time s;  //创建一个局部对象,作为返回值
    57     long total_time = hour * 60 * d + minitue * d;//这种都hour和minitue都相乘的方法是从书中学到的
    58     s.hour = total_time / 60;
    59     s.minitue = total_time % 60;  
    60 
    61     return s;
    62 }
    63 
    64 //只是增加小时
    65 void Time::Addhour(int h)
    66 {
    67     hour = hour + h;
    68 }
    69 
    70 //只是增加分钟
    71 void Time::Addminitue(int m)
    72 {
    73     minitue = minitue + m;
    74     hour = hour + minitue / 60;  //如果增加的分钟数超过了60则对minitue以60为底取整
    75     minitue = minitue % 60;  //如果增加的分钟数超过了60则对minitue以60为底取余
    76 }
    77 
    78 //重置时间
    79 void Time::Reset(int h, int m)
    80 {
    81     hour = h;
    82     minitue = m;
    83 }
    84 
    85 //显示对象中的数据
    86 void Time::show()
    87 {
    88     std::cout << "hour= " << hour << " minitue= " << minitue << std::endl;
    89 }
    mytime.cpp
     1 //user_main.cpp
     2 //使用运算符重载版本
     3 //用s1=s2+s3代替s1 = s2.Sum(s3);即可
     4 //s1=s2+s3;实际上是调用函数的方法:s1=s2.operator+(s3);
     5 #include <iostream>
     6 #include "mytime.h"
     7 
     8 int main()
     9 {
    10     Time s1;  //定义一个Time类对象,并用默认构造函数进行初始化
    11     Time s2(2, 40);  //定义一个Time类对象,并隐式的调用构造函数
    12     Time s3(5, 55);  //定义一个Time类对象,并隐式的调用构造函数
    13 
    14     std::cout << "使用+重载运算符:" << std::endl;
    15     s1 = s2 + s3; //等价于s1=s2.operator+(s3); s2和s3可以互换位置
    16     s1.show();
    17 
    18     std::cout << "使用类方法Addhour():" << std::endl;
    19     s1.Addhour(3);  //对s1对象中的数据,只是增加小时
    20     s1.show();
    21 
    22     std::cout << "使用-运算符重载方法:" << std::endl;
    23     s1 = s1 - s2;  //等价于s1=s1.operator-(s2);s1和s2可以互换位置
    24     s1.show();
    25 
    26     std::cout << "使用*运算符重载方法:" << std::endl;
    27     s1 = s1 * 2;   //等价于s1 = s1.operator-(2);
    28     s1.show();
    29     //这里s1只能是在*的左边,2只能是在*的右边
    30     //在*的左边的标识符是要调用operator*()方法的,显然数字不能调用该方法
    31     //此项缺陷也为以后的友元函数的提出打下了基础
    32 
    33     system("pause");
    34     return 0;
    35 }
    36 /* 总结 */
    37 /*
    38 01)关于引用的使用方法:int & rt = 3; 这样使用是不合法的,要注意在函数参数传递的时候不要发生这样的错误
    39 02)关于函数返回值的问题:如果一个变量(包括对象)是在该函数内创建的,那么是不可以以引用的方式返回的
    40    因为引用返回的都是该变量本身,而该变量在对应的函数执行完毕之后就消失了,从而发生错误。
    41    但是如果变量(对象)是从主函数中传入的,并且返回的也是从主函数中传入的变量(对象),那么是可以以引用
    42    的方式返回的。
    43 03)
    44 */
    user_main.cpp

    执行结果为:

     友元函数

    01)问题的提出:
      对于上一个代码中的对*的函数重载中 Time operator*(double d) const;
      对Time对象s1和s2,以及一个double值2.1
      使用方法只能是s1 = s2*2.1;//实际上是调用对*的重载函数:s1=s2.operator(2.1);
      所以s1 = 2.1*s2; 是会报错的
    02)解决方法:
      A 写注释:告诉每个人只能按照s2*2.1这种方式去写,不能写成2.1*s2
      B 使用非成员函数,非成员函数不是由对象调用的,它使用的值都必须是由实参的形式传入的
          但是也引发了一个新问题:非成员函数不能访问私有数据。最终的解决方法是使用友元函数

          此处引入友元函数的目的是实现乘法的交换律

         C 友元函数是一种介于类非成员函数和类成员函数之间的一种函数,友元函数不是类成员函数,但是可以访问类私有数据(拥有             类成员函数的权限)

    03)友元函数的声明方法:使用关键字friend
      friend Time operator*(doubla m,const Time & t);//该友元函数同时对*运算符进行了重载
      该声明意味着下面两点:
      A 虽然operator*()是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用; ***
      B 虽然operatir*()不是成员函数,但它有成员函数的访问权限。(可以访问私有数据)  ***
    04)友元函数的定义方法:不用使用关键字friend,因为它不是成员函数,所以也不用使用Time::限定符
      Time operator*(double m, Time & t) const
      {
        Time result;
        long total_time = t.hour * m + t.minitue * m;
        result.hour = total_time / 60;
        result.minitue = total_time % 60;
        return result;
         }
    05)友元函数调用方法:
     有了友元函数之后,就可以直接使用 s1 = 2.1*s2;
     编译器将s1 = 2.1*s2;转换成s1 = operator*(2.1,s2);友元函数版本
    06)稍作修改,就可以将友元函数改变成非友元函数:
        //在该非友元函数中调用对*的重载函数
      Time operator*(double m, Time & t) const
      {
        return t*m;  //即实际调用的函数为 t.operator*(m),即调用的函数是对*的重载的函数
        //原来的版本是显式的访问t.hour和t.minitue.由于这里是将对象t整体使用的,所以t*m将调用对*的重载函数
      }
    07)总结:
      如果在类声明中即声明了对*的重载函数Time operator*(double d) const;
      在类声明在又声明了友元函数:friend Time operator*(doubla m,const Time & t);
      该友元函数同时对*运算符进行了重载,那么在主函数中就可以使用下面的两种方式
      s1 = s2 * 2.1; //调用对*的重载函数,编译器将其转换为s1 = s2.operator(2.1);
      s1 = 2.1 * s2; //调用友元函数,编译器将其转换为:s1 = operator(2.1,s2);
      即实现了乘法的交换律。

     1 //mytime.h
     2 //使用运算符重载版本
     3 //用 Time operater+(Time & s) const 代替Time Sum(Time & T);即可
     4 #ifndef MYTIME_H_
     5 #define MYTIME_H_
     6 
     7 class Time
     8 {
     9 private:
    10     int hour; 
    11     int minitue;
    12 public:
    13     Time();  //声明默认构造函数
    14     Time(int  h, int  m);  //声明构造函数
    15     Time operator+(const Time & T) const;  
    16     Time operator-(const Time & T) const; //两个const可有可无
    17     Time operator*(double d) const;  //最后一个const还是表明不能修改调用operator*()方法的对象中的数据
    18     friend Time operator*(double m, const Time & t); //声明一个友元函数,只允许中声明的时候使用friend关键字
    19     void Addhour(int h);  //单独的增加小时
    20     void Addminitue(int m);  //单独的增加分钟
    21     void Reset(int h=0, int m=0);  //重置时间
    22     void show();
    23 };
    24 
    25 #endif
    26 
    27 
    28 /* 友元函数 */
    29 /*
    30 01)问题的提出:
    31    对于上一个代码中的对*的函数重载中 Time operator*(double d) const;
    32    对Time对象s1和s2,以及一个double值2.1
    33    使用方法只能是s1 = s2*2.1;//实际上是调用对*的重载函数:s1=s2.operator(2.1);
    34    所以s1 = 2.1*s2; 是会报错的
    35 02)解决方法:
    36    A 写注释:告诉每个人只能按照s2*2.1这种方式去写,不能写成2.1*s2
    37    B 使用非成员函数,非成员函数不是由对象调用的,它使用的值都必须是由实参的形式传入的
    38      但是也引发了一个新问题:非成员函数不能访问私有数据。最终的解决方法是使用友元函数
    39 03)友元函数的声明方法:使用关键字friend
    40    friend Time operator*(doubla m,const Time & t);//该友元函数同时对*运算符进行了重载
    41    该声明意味着下面两点:
    42    A 虽然operator*()是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用;
    43    B 虽然operatir*()不是成员函数,但它有成员函数的访问权限。(可以访问私有数据)
    44 04)友元函数的定义方法:不用使用关键字friend,因为它不是成员函数,所以也不用使用Time::限定符
    45    Time operator*(double m, Time & t) const
    46    {
    47        Time result;
    48        long total_time = t.hour * m + t.minitue * m;
    49        result.hour = total_time / 60;
    50        result.minitue = total_time % 60;
    51        return result;
    52    }
    53 05)友元函数调用方法:
    54    有了友元函数之后,就可以直接使用 s1 = 2.1*s2;
    55    编译器将s1 = 2.1*s2;转换成s1 = operator*(2.1,s2);友元函数版本
    56 06)稍作修改,就可以将友元函数改变成非友元函数:
    57    //在该非友元函数中调用对*的重载函数
    58    Time operator*(double m, Time & t) const  
    59    {
    60        return t*m; 
    61        //原来的版本是显式的访问t.hour和t.minitue.由于这里是将对象t整体使用的,所以t*m将调用对*的重载函数
    62        //即实际调用的函数为 t.operator*(m)
    63    }
    64 07)总结:
    65    如果在类声明中即声明了对*的重载函数Time operator*(double d) const;
    66    在类声明在又声明了友元函数:friend Time operator*(doubla m,const Time & t);
    67    该友元函数同时对*运算符进行了重载,那么在主函数中就可以使用下面的两种方式
    68    s1 = s2 * 2.1;  //调用对*的重载函数,编译器将其转换为s1 = s2.operator(2.1);
    69    s1 = 2.1 * s2;  //调用友元函数,编译器将其转换为:s1 = operator(2.1,s2);
    70    即实现了乘法的交换律。
    71 */
    mytime.h
      1 //mytime.cpp
      2 //使用运算符重载版本
      3 //用 Time operater+(Time & s) const 代替Time Sum(Time & T);即可
      4 //重载-运算符Time Time::operator-(const Time & T) const 
      5 //重载*运算符Time Time::operator*(double d) const
      6 #include <iostream>
      7 #include "mytime.h"
      8 
      9 Time::Time()  //默认构造函数的定义,创建类对象时,默认执行以下操作
     10 {
     11     hour = 0;
     12     minitue = 0;
     13 }
     14 
     15 
     16 /*Time::Time(int & h, int & m) *///构造函数定义,创建类对象时,使用构造函数时执行以下操作.
     17 //声明构造函数,如果是这样声明构造函数的话,在主函数中调用构造函数,传入一个数字是不合法的
     18 //即 int & h = 4;  这样是不合法的
     19 Time::Time(int  h, int  m)  //这样在声明类对象的时候,调用该构造函数才是合法的,因为将数字传递给引用是不合法的
     20 {
     21     hour = h;
     22     minitue = m;
     23 }
     24 
     25 Time Time::operator+(const Time & T) const
     26 {
     27     Time s;  //新建一个TIme对象,用于作为该函数的返回值
     28     s.minitue = minitue + T.minitue;
     29     s.hour = hour + T.hour + s.minitue / 60; 
     30     //hour是调用Sum()方法的对象中的数据,T.hour是作为实参传入的对象中的数据
     31     //最后再加上调用对象的分钟数,和,作为实参传入的分钟数的和,然后取整
     32     s.minitue = s.minitue % 60;  //对两个对象中数据的分钟数取余
     33 
     34     return s;
     35 }
     36 //注意:Sum()函数的返回值不能是Time & (指向Time对象的引用),这是由于返回的对象时s,而s是一个在Sum()
     37 //中定义的局部变量,Sum()函数执行完毕后,s将会消失,返回一个消失的引用是不合适的
     38 //所以这里返回s对象的副本,之后在主函数中可以使用它 
     39 //以前函数的返回值可以为引用,是因为返回的对象均为从主函数中传入的对象,这些对象都是在主函数中定义的
     40 //所以可以返回,比如this指针那里,传入一个对象和this指针指向的调用类方法的对象
     41 
     42 //对-运算符进行重载
     43 Time Time::operator-(const Time & T) const 
     44 {
     45     Time s;  //创建一个局部对象,作为返回值
     46     s.minitue = minitue - T.minitue;  
     47     s.hour = hour - T.hour + s.minitue/60; //虽然是减,但是为了以防万一,还是加上这个取整吧
     48     s.minitue = s.minitue % 60;
     49 
     50     return s;
     51 }
     52 
     53 //对*运算符进行重载
     54 Time Time::operator*(double d) const
     55 {
     56     Time s;  //创建一个局部对象,作为返回值
     57     long total_time = hour * 60 * d + minitue * d;//这种都hour和minitue都相乘的方法是从书中学到的
     58     s.hour = total_time / 60;
     59     s.minitue = total_time % 60;  
     60 
     61     return s;
     62 }
     63 
     64 //只是增加小时
     65 void Time::Addhour(int h)
     66 {
     67     hour = hour + h;
     68 }
     69 
     70 //只是增加分钟
     71 void Time::Addminitue(int m)
     72 {
     73     minitue = minitue + m;
     74     hour = hour + minitue / 60;  //如果增加的分钟数超过了60则对minitue以60为底取整
     75     minitue = minitue % 60;  //如果增加的分钟数超过了60则对minitue以60为底取余
     76 }
     77 
     78 //重置时间
     79 void Time::Reset(int h, int m)
     80 {
     81     hour = h;
     82     minitue = m;
     83 }
     84 
     85 //友元函数的定义
     86 //由于友元函数不是类成员函数,所以不能使用Time::限定符
     87 //在友元函数的定义中也不能出现关键字friend
     88 //但是友元函数却可以访问Time类中的私有数据和公有数据
     89 Time operator*(double m, const Time & t)
     90 {
     91     Time result;
     92     long total_time = t.hour * 60 * m + t.minitue * m;
     93     result.hour = total_time / 60;
     94     result.minitue = total_time % 60;
     95 
     96     return result;
     97 }
     98 
     99 //显示对象中的数据
    100 void Time::show()
    101 {
    102     std::cout << "hour= " << hour << " minitue= " << minitue << std::endl;
    103 }
    mytime.cpp
     1 //user_main.cpp
     2 //使用运算符重载版本
     3 //用s1=s2+s3代替s1 = s2.Sum(s3);即可
     4 //s1=s2+s3;实际上是调用函数的方法:s1=s2.operator+(s3);
     5 #include <iostream>
     6 #include "mytime.h"
     7 
     8 int main()
     9 {
    10     Time s1;  //定义一个Time类对象,并用默认构造函数进行初始化
    11     Time s2(2, 40);  //定义一个Time类对象,并隐式的调用构造函数
    12     Time s3(5, 55);  //定义一个Time类对象,并隐式的调用构造函数
    13 
    14     std::cout << "使用*运算符重载方法:" << std::endl;
    15     s1 = s2 * 2;   //等价于s1 = s1.operator*(2);
    16     s1.show();
    17 
    18     s2.Reset(2,40);  //对象s2调用类方法Reset(),并使用实参覆盖掉默认参数
    19 
    20     std::cout << "使用友元函数:" << std::endl;
    21     s1 = 2 * s2;   //等价于s1 = operator*(2,s2);
    22     s1.show();
    23 
    24 
    25     system("pause");
    26     return 0;
    27 }
    usre_main.cpp

    执行结果为:

    对<<运算符的重载&友元函数 

    01)问题的提出:
       在以前的程序版本中,加入要为显示一个Time对象trip的值,我们都是用的一个类方法show(),对象调用类方法
       的方式为trip.show()。能不能用cout<<trip;呢,答案是可以的,因为<<也是C++运算符之一
    02)运算符<<的历史和cout对象的相关介绍
       最初<<运算符是c和c++位运算符,将值中的位左移。ostream类对该运算符进行了重载,将其转换为一个输出工具。
       而cout又是类ostream的一个对象,能够识别C++基本类型。这是因为对于每种C++基本类型,ostream类声明中
       都包含了相应的重载operator<<()定义。也就是说,一个定义使用int型参数,一个定义使用double型参数,一个定义
       使用char型参数等等。因此要让cout能够识别TIme对象,一种方法是将一个新的函数运算符定义添加到ostream
       类声明中,但修改ostream类是一个坏主意;一种方法是让Time知道任何使用cout,即在Time中声明对<<的重载函数
    03)那么在Time类中声明友元函数还是非友元函数?
       如果是声明常规的类方法,则在<<运算符的左边一定是一个Time对象,那么输出就是下面的那样了:
       trip<<cout; //这样显然是不合适的
       所以要使用友元函数:
       void operator<<(ostream & os, const Time & t) //其中ostream是一个类
       {
       os << t.hour <<" hours" << t.minitue <<"minitues ";
       }
       这样就可以使用下面的语句了:
       cout<<trip; //显示对象trip中的数据了
       调用cout<<trip应使用cout对象本身,而不是cout的副本,因此应该使用ostream & os以用,而不是按值传递
       Time对象可以按值传递或者是按引用传递,按引用传递比按值传递使用的时间和内存都要少,因此使用按引用传递。
    04)改进
      很显然,上面对<<重载友元函数对于下面这样的语句是无能为力的:
       cout<<"Trip time: "<<trip<<"(Tuesday) ";
    05)解决方法让cout<<"Trip time: "返回一个cout即可解决问题。反应在对<<重载友元函数来说就是返回值为
       指向ostream对象的引用即可,即下面改进的对<<重载友元函数版本:
      ostream & operator<<(ostream & os, const Time & t) //其中ostream是一个类
      {
        os << t.hour <<" hours" << t.minitue <<"minitues ";
        return os;
      }
       注意:返回值不再是void了,而是指向ostream对象的引用
    06)上面的这个operator<<()函数版本还可以用于将输出写如到文件中:
      #include <fstream> //for ofstream
      ...
      ofstream fout; //创建一个ofstream类对象fout
      fout.open("savetime.txt"); //对象fout和一个txt文件关联
      Time trip(12,40); //创建一个Time类对象trip,并隐式的调用构造函数初始化trip对象
      fout<<trip; //实际调用方式为 operator<<(fout,trip);

      1 //mytime.h
      2 //包含了operator*()和operatro<<()两个友元函数
      3 //将operator*()作为内联函数,因为其代码很短(定义也是原型时,要使用关键字friend)
      4 
      5 #ifndef MYTIME_H_
      6 #define MYTIME_H_
      7 #include <iostream>  //这里声明了,在mytime.cpp就只包含mytime.h头文件,便可以提供iostream头文件的支持
      8 
      9 class Time
     10 {
     11 private:
     12     int hour; 
     13     int minitue;
     14 public:
     15     Time();  //声明默认构造函数
     16     Time(int  h, int  m);  //声明构造函数
     17     Time operator+(const Time & T) const;  
     18     Time operator-(const Time & T) const; //两个const可有可无
     19     Time operator*(double d) const;  //最后一个const还是表明不能修改调用operator*()方法的对象中的数据
     20     friend Time operator*(double m, const Time & t)  //即使原型是定义,要使用关键字friend,同时也是内联函数
     21     {
     22         return t * m;  //实际上调用方法为t.operator*(m),即调用对*的重载函数
     23     }
     24     friend std::ostream & operator<<(std::ostream & os, Time & t);//声明一个对运算符<<重载的友元函数
     25     void Addhour(int h);  //单独的增加小时
     26     void Addminitue(int m);  //单独的增加分钟
     27     void Reset(int h=0, int m=0);  //重置时间
     28     void show();
     29 };
     30 
     31 #endif
     32 
     33 
     34 /* 友元函数 */
     35 /*
     36 01)问题的提出:
     37    对于上一个代码中的对*的函数重载中 Time operator*(double d) const;
     38    对Time对象s1和s2,以及一个double值2.1
     39    使用方法只能是s1 = s2*2.1;//实际上是调用对*的重载函数:s1=s2.operator(2.1);
     40    所以s1 = 2.1*s2; 是会报错的
     41 02)解决方法:
     42    A 写注释:告诉每个人只能按照s2*2.1这种方式去写,不能写成2.1*s2
     43    B 使用非成员函数,非成员函数不是由对象调用的,它使用的值都必须是由实参的形式传入的
     44      但是也引发了一个新问题:非成员函数不能访问私有数据。最终的解决方法是使用友元函数
     45 03)友元函数的声明方法:使用关键字friend
     46    friend Time operator*(doubla m,const Time & t);//该友元函数同时对*运算符进行了重载
     47    该声明意味着下面两点:
     48    A 虽然operator*()是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用;
     49    B 虽然operatir*()不是成员函数,但它有成员函数的访问权限。(可以访问私有数据)
     50 04)友元函数的定义方法:不用使用关键字friend,因为它不是成员函数,所以也不用使用Time::限定符
     51    Time operator*(double m, Time & t) const
     52    {
     53        Time result;
     54        long total_time = t.hour * m + t.minitue * m;
     55        result.hour = total_time / 60;
     56        result.minitue = total_time % 60;
     57        return result;
     58    }
     59 05)友元函数调用方法:
     60    有了友元函数之后,就可以直接使用 s1 = 2.1*s2;
     61    编译器将s1 = 2.1*s2;转换成s1 = operator*(2.1,s2);友元函数版本
     62 06)稍作修改,就可以将友元函数改变成非友元函数:
     63    //在该非友元函数中调用对*的重载函数
     64    Time operator*(double m, Time & t) const  
     65    {
     66        return t*m; 
     67        //原来的版本是显式的访问t.hour和t.minitue.由于这里是将对象t整体使用的,所以t*m将调用对*的重载函数
     68        //即实际调用的函数为 t.operator*(m)
     69    }
     70 07)总结:
     71    如果在类声明中即声明了对*的重载函数Time operator*(double d) const;
     72    在类声明在又声明了友元函数:friend Time operator*(doubla m,const Time & t);
     73    该友元函数同时对*运算符进行了重载,那么在主函数中就可以使用下面的两种方式
     74    s1 = s2 * 2.1;  //调用对*的重载函数,编译器将其转换为s1 = s2.operator(2.1);
     75    s1 = 2.1 * s2;  //调用友元函数,编译器将其转换为:s1 = operator(2.1,s2);
     76    即实现了乘法的交换律。
     77 */
     78 
     79 /* 对<<运算符的重载&友元函数 */
     80 /*
     81 01)问题的提出:
     82    在以前的程序版本中,加入要为显示一个Time对象trip的值,我们都是用的一个类方法show(),对象调用类方法
     83    的方式为trip.show()。能不能用cout<<trip;呢,答案是可以的,因为<<也是C++运算符之一
     84 02)运算符<<的历史和cout对象的相关介绍
     85    最初<<运算符是c和c++位运算符,将值中的位左移。ostream类对该运算符进行了重载,将其转换为一个输出工具。
     86    而cout又是类ostream的一个对象,能够识别C++基本类型。这是因为对于每种C++基本类型,ostream类声明中
     87    都包含了相应的重载operator<<()定义。也就是说,一个定义使用int型参数,一个定义使用double型参数,一个定义
     88    使用char型参数等等。因此要让cout能够识别TIme对象,一种方法是将一个新的函数运算符定义添加到ostream
     89    类声明中,但修改ostream类是一个坏主意;一种方法是让Time知道任何使用cout,即在Time中声明对<<的重载函数
     90 03)那么在Time类中声明友元函数还是非友元函数?
     91    如果是声明常规的类方法,则在<<运算符的左边一定是一个Time对象,那么输出就是下面的那样了:
     92    trip<<cout;  //这样显然是不合适的
     93    所以要使用友元函数:
     94    void operator<<(ostream & os, const Time & t) //其中ostream是一个类
     95    {
     96      os << t.hour <<" hours" << t.minitue <<"minitues
    ";
     97    }
     98    这样就可以使用下面的语句了:
     99    cout<<trip;  //显示对象trip中的数据了
    100    调用cout<<trip应使用cout对象本身,而不是cout的副本,因此应该使用ostream & os以用,而不是按值传递
    101    Time对象可以按值传递或者是按引用传递,按引用传递比按值传递使用的时间和内存都要少,因此使用按引用传递。
    102 04)改进
    103    很显然,上面对<<重载友元函数对于下面这样的语句是无能为力的:
    104    cout<<"Trip time: "<<trip<<"(Tuesday)
    ";
    105 05)解决方法:让cout<<"Trip time: "返回一个cout即可解决问题。反应在对<<重载友元函数来说就是返回值为
    106    指向ostream对象的引用即可,即下面改进的对<<重载友元函数版本:
    107    ostream & operator<<(ostream & os, const Time & t) //其中ostream是一个类
    108    {
    109      os << t.hour <<" hours" << t.minitue <<"minitues
    ";
    110      return os;
    111    }
    112    注意:返回值不再是void了,而是指向ostream对象的引用
    113 06)上面的这个operator<<()函数版本还可以用于将输出写如到文件中:
    114    #include <fstream> //for ofstream
    115    ...
    116    ofstream fout;  //创建一个ofstream类对象fout
    117    fout.open("savetime.txt");  //对象fout和一个txt文件关联
    118    Time trip(12,40);  //创建一个Time类对象trip,并隐式的调用构造函数初始化trip对象
    119    fout<<trip;  //实际调用方式为 operator<<(fout,trip);
    120 
    121 */
    mytime.h
      1 //mytime.cpp
      2 //使用运算符重载版本
      3 //用 Time operater+(Time & s) const 代替Time Sum(Time & T);即可
      4 //重载-运算符Time Time::operator-(const Time & T) const 
      5 //重载*运算符Time Time::operator*(double d) const
      6 //#include <iostream> //可以不包含该头文件了,因为在mytime.h头文件中引用了该头文件,且在本文件中包含了mytime.h头文件
      7 #include "mytime.h" 
      8 
      9 Time::Time()  //默认构造函数的定义,创建类对象时,默认执行以下操作
     10 {
     11     hour = 0;
     12     minitue = 0;
     13 }
     14 
     15 
     16 /*Time::Time(int & h, int & m) *///构造函数定义,创建类对象时,使用构造函数时执行以下操作.
     17 //声明构造函数,如果是这样声明构造函数的话,在主函数中调用构造函数,传入一个数字是不合法的
     18 //即 int & h = 4;  这样是不合法的
     19 Time::Time(int  h, int  m)  //这样在声明类对象的时候,调用该构造函数才是合法的,因为将数字传递给引用是不合法的
     20 {
     21     hour = h;
     22     minitue = m;
     23 }
     24 
     25 Time Time::operator+(const Time & T) const
     26 {
     27     Time s;  //新建一个TIme对象,用于作为该函数的返回值
     28     s.minitue = minitue + T.minitue;
     29     s.hour = hour + T.hour + s.minitue / 60;
     30     //hour是调用Sum()方法的对象中的数据,T.hour是作为实参传入的对象中的数据
     31     //最后再加上调用对象的分钟数,和,作为实参传入的分钟数的和,然后取整
     32     s.minitue = s.minitue % 60;  //对两个对象中数据的分钟数取余
     33 
     34     return s;
     35 }
     36 
     37 //对-运算符进行重载
     38 Time Time::operator-(const Time & T) const 
     39 {
     40     Time s;  //创建一个局部对象,作为返回值
     41     s.minitue = minitue - T.minitue;  
     42     s.hour = hour - T.hour + s.minitue/60; //虽然是减,但是为了以防万一,还是加上这个取整吧
     43     s.minitue = s.minitue % 60;
     44 
     45     return s;
     46 }
     47 
     48 //对*运算符进行重载
     49 Time Time::operator*(double d) const
     50 {
     51     Time s;  //创建一个局部对象,作为返回值
     52     long total_time = hour * 60 * d + minitue * d;//这种都hour和minitue都相乘的方法是从书中学到的
     53     s.hour = total_time / 60;
     54     s.minitue = total_time % 60;  
     55 
     56     return s;
     57 }
     58 
     59 //只是增加小时,常规类方法
     60 void Time::Addhour(int h)
     61 {
     62     hour = hour + h;
     63 }
     64 
     65 //只是增加分钟,常规类方法
     66 void Time::Addminitue(int m)
     67 {
     68     minitue = minitue + m;
     69     hour = hour + minitue / 60;  //如果增加的分钟数超过了60则对minitue以60为底取整
     70     minitue = minitue % 60;  //如果增加的分钟数超过了60则对minitue以60为底取余
     71 }
     72 
     73 //重置时间,常规类方法
     74 void Time::Reset(int h, int m)
     75 {
     76     hour = h;
     77     minitue = m;
     78 }
     79 
     80 //友元函数的定义
     81 //由于友元函数不是类成员函数,所以不能使用Time::限定符
     82 //在友元函数的定义中也不能出现关键字friend
     83 //但是友元函数却可以访问Time类中的私有数据和公有数据
     84 //Time operator*(double m, const Time & t)  //该函数已经在头文件中声明和定义
     85 //{
     86 //    Time result;
     87 //    long total_time = t.hour * 60 * m + t.minitue * m;
     88 //    result.hour = total_time / 60;
     89 //    result.minitue = total_time % 60;
     90 //
     91 //    return result;
     92 //}
     93 
     94 //cout<<trip实现
     95 //对<<运算符进行重载的友元函数定义
     96 //由于ostream在名称空间std中,所以要使用std::限定符
     97 //对于os,将被从主函数传入的实参代替,由于该实参是在转函数中产生,所以operator<<()函数执行完毕后
     98 //该实参也存在,所以返回值的类型可以是引用
     99 //如果是在一个子函数中创建的局部变量,则返回类型就不能是引用了
    100 std::ostream & operator<<(std::ostream & os, Time & t)
    101 {
    102     os << t.hour << " hours" << t.minitue << " minitues
    ";
    103     return os;  
    104 }
    105 
    106 //显示对象中的数据
    107 void Time::show()
    108 {
    109     std::cout << "hour= " << hour << " minitue= " << minitue << std::endl;
    110 }
    mytime.cpp
     1 //user_main.cpp
     2 //使用运算符重载版本
     3 //用s1=s2+s3代替s1 = s2.Sum(s3);即可
     4 //s1=s2+s3;实际上是调用函数的方法:s1=s2.operator+(s3);
     5 #include <iostream>
     6 #include "mytime.h"
     7 
     8 int main()
     9 {
    10     using std::cout;
    11     using std::endl;
    12 
    13     Time s1;  //定义一个Time类对象,并用默认构造函数进行初始化
    14     Time s2(2, 40);  //定义一个Time类对象,并隐式的调用构造函数
    15     Time s3(5, 55);  //定义一个Time类对象,并隐式的调用构造函数
    16 
    17     std::cout << "使用*运算符重载方法:" << std::endl;
    18     s1 = s2 * 2;   //等价于s1 = s1.operator*(2);
    19     cout << s1;  //和使用s1.show()的作用是一样的
    20 
    21     s2.Reset(2,40);  //对象s2调用类方法Reset(),并使用实参覆盖掉默认参数
    22 
    23     std::cout << "使用友元函数:" << std::endl;
    24     s1 = 2 * s2;   //等价于s1 = operator*(2,s2);
    25     cout << s1;  //和使用s1.show()的作用是一样的
    26      
    27 
    28     system("pause");
    29     return 0;
    30 }
    user_main.cpp

    执行结果为:

     cin.clear()的用法 

    我们谈谈cin.clear的作用,第一次看到这东西,很多人以为就是清空cin里面的数据流,而实际上却与此相差很远,首先我们看看以下代码:

    #include <iostream> 
    using namespace std; 
    int main()  
    {         
        int a;         
        cin>>a;         
        cout<<cin.rdstate()<<endl;         
        if(cin.rdstate() == ios::goodbit)   
        {   
            cout<<"输入数据的类型正确,无错误!"<<endl;               
        }         
        if(cin.rdstate() == ios_base::failbit)         
        {                 
            cout<<"输入数据类型错误,非致命错误,可清除输入缓冲区挽回!"<<endl;         
        }         
        system("pause"); 
    }
     
    我们定义要输入到的变量是整型,但如果我们输入了英文字母或者汉字,那就会发生错误,cin里有个方法能检测这个错误,就是cin.rdstate(); 当cin.rdstate()返回0(即ios::goodbit)时表示无错误,可以继续输入或者操作,若返回4则发生非致命错误即ios::failbit,则不能继续输入或操作.而cin.clear则可以控制我们此时cin里对这个问题的一个标识.语发如下: cin.clear(标识符); 标识符号为:

    goodbit 无错误 
    Eofbit 已到达文件尾 
    failbit 非致命的输入/输出错误,可挽回 
    badbit 致命的输入/输出错误,无法挽回 若在输入输出类里.需要加ios::标识符号 
    通过cin.clear,我们能确认它的内部标识符,如果输入错误则能重新输入.结合真正的清空数据流方法cin.sync(),请看下例:
    #include <iostream> 
    using namespace std; 
    int main()  
    {         
        int a;         
        while(1)         
        {                 
            cin>>a;                 
            if(!cin)            //条件可改写为cin.fail()                 
            {                         
                cout<<"输入有错!请重新输入"<<endl;                         
                cin.clear();                          
                cin.sync();   //清空流                 
            }                 
            else                 
            {                         
                cout<<a;                         
                break;                 
            }         
        }         
        system("pause"); 
    }
    上面的cin.clear()默认参数为0,即无错误,正常操作.当我们输入英文字母'k'时,它的状态标识改为fail,即错误,用cout对用户输出信息,再用cin.clear让错误标识改回为0,让我们可以继续输入,再清空流数据继续输入.如果我们没有了cin.clear,则会进入死循环,其过程为我们输入了英文字母,它的状态标识便为fail,当运行到条件判断时,便总是回到错误的条件表示里,并且我们再也没办法输入,因为错误的表示关闭了cin,所以会进入死循环.极坐标和直角坐标的相互转换(随机漫步的实现)

    极坐标和直角坐标的相互转换(随机漫步的实现)

    /* 总结 */
    01)对象是不可以直接调用类中的私有变量的,只能调用公有函数!!
       所以加入对象result要使用x值怎么办?result.x是不合法的,所以使用result.xval();
    02)使用了名称空间来创建类,或在名称空间中创建类,那么类中的方法定义的时候,一种方法是和h文件中写的一样:使用
       namespace VECT{ ... }; 另一种方法就是在cpp文件中使用using声明
    03)如果使用using声明,那么定义友元函数的时候,在友元函数名之前是要加上名称空间的名字+双冒号的,否则友元函数
       不能访问类中的私有数据

     1 //vect.h
     2 //极坐标和直角坐标的相互转换
     3 
     4 #ifndef VECTOR_H_
     5 #define VECTOR_H_
     6 
     7 //定义一个名称空间VECTOR,将类定义放在名称空间中
     8 namespace VECTOR  
     9 {
    10     class Vector
    11     {
    12     public:
    13         enum Mode {RECT,POL}; //定义枚举量Mode,可以用Mode去定义变量,例如Mode M; 但是只能用RECT和POL对M赋值
    14     private:
    15         double x; //直角坐标系的横坐标
    16         double y; //直角坐标系的纵坐标
    17         double mag;  //极坐标系的长度
    18         double ang;  //极坐标系的角度
    19         Mode mode;  //用枚举量定义一个枚举变量,mode的值只能是RECT或POL
    20         void set_mag();  //设置极坐标系的长度函数
    21         void set_ang();  //设置极坐标系的角度函数
    22         void set_x();
    23         void set_y();  
    24     public:
    25         Vector();  //默认构造函数的声明
    26         ~Vector();  //析构函数的声明
    27     //声明构造函数,n1和n2是传入的直角坐标系或者是极坐标系的坐标,默认是RECT(直角坐标系模式)
    28         Vector(double n1, double n2, Mode form = RECT); 
    29     //声明重置函数,作用类似于析构函数,只不过reset()可以随时使用,而是构函数只有在类创建对象的时候才会被使用
    30         void reset(double n1, double n2, Mode form = RECT);
    31     //定义返回x、y、mag、ang的值的函数,由于是在类中定义,自动成为内联函数
    32     //const放在了函数名括号的后面,表示该函数不可以修改调用该函数对象的参数
    33     //对象是不可以直接调用类中的私有变量的,只能调用公有函数!!
    34     //所以加入对象result要使用x值怎么办?result.x是不合法的,所以使用result.xval();
    35         double xval() const { return x; }  
    36         double yval() const { return y; }
    37         double magval() const { return mag; }
    38         double angval() const { return ang; }
    39     //直角坐标系或者是极坐标系模式的选择
    40         void polar_mode();
    41         void rect_mode();
    42     //运算符重载
    43         Vector operator+(const Vector & b) const;  //第一个Vector表示operator+()函数的返回值为Vector类对象
    44         Vector operator-(const Vector & b) const;
    45         Vector operator-() const;  //对类对象中的数据进行去反操作,即正负的变换
    46         Vector operator*(double n) const;
    47     //友元函数的声明
    48         friend Vector operator*(double n,const Vector & b);
    49         friend std::ostream & operator<<(std::ostream & os, const Vector & v);
    50     };
    51 }
    52 
    53 #endif
    54 
    55 /* 总结 */
    56 /*
    57 01)对象是不可以直接调用类中的私有变量的,只能调用公有函数!!
    58    所以加入对象result要使用x值怎么办?result.x是不合法的,所以使用result.xval();
    59 02)使用了名称空间来创建类,或在名称空间中创建类,那么类中的方法定义的时候,一种方法是和h文件中写的一样:使用
    60    namespace VECT{ ... }; 另一种方法就是在cpp文件中使用using声明
    61 03)如果使用using声明,那么定义友元函数的时候,在友元函数名之前是要加上名称空间的名字+双冒号的,否则友元函数
    62    不能访问类中的私有数据
    63 */
    vect.h
      1 //vector.cpp
      2 #include <iostream>
      3 #include <cmath>  //for sqrt()、sin()、cos()、atan()、atan()、
      4 #include "vect.h"
      5 
      6 
      7 using VECTOR::Vector;  //声明名称空间中的类,以后就可以直接使用类中的方法
      8 using std::sqrt;  //开根号
      9 using std::sin;
     10 using std::cos;
     11 using std::atan;  //atan(x)表示求x的反正切,返回值为[-pi/2,pi/2]区间的一个值,返回弧度值
     12 using std::atan2;  //atan2(y,x)表示求y/x的正切,返回值为[-pi,pi]区间的一个值,y是纵坐标的值
     13 using std::cout;
     14 using std::endl;
     15 
     16 //输入的是度数,而程序中要用弧度值,所以需要180/pi,例如将60°转换为弧度值方法为60/rad_to_deg
     17 const double rad_to_deg = 180.0 / 3.14;  
     18 
     19 //默认构造函数定义
     20 Vector::Vector()
     21 {
     22     x = y = mag = ang = 0;
     23     mode = RECT;  //刚刚这一句丢了
     24 }
     25 
     26 //析构函数定义
     27 Vector::~Vector()
     28 {
     29 
     30 }
     31 
     32 //构造函数定义
     33 Vector::Vector(double n1, double n2, Mode form)
     34 {
     35     mode = form;
     36     if (form == RECT)
     37     {
     38         x = n1;    //将传入的直角坐标系的参数传递给类中的成员变量x和y
     39         y = n2;
     40         set_mag(); //设置x和y对应的极坐标系中的值
     41         set_ang();
     42     }
     43     else if (form == POL)
     44     {
     45         mag = n1;
     46         ang = n2 / rad_to_deg;  //将度数转换为弧度制
     47         set_x();
     48         set_y();
     49     }
     50     else
     51     {
     52         cout << "您输入有误,将坐标系的值全部设置为0" << endl;
     53         x = y = mag = ang = 0;
     54     }
     55         
     56 }
     57 
     58 //重置函数的定义  这个方法不能用
     59 //void Vector::reset(double n1, double n2, Mode f)
     60 //{
     61 //    Vector(n1, n2, f);  //调用构造函数
     62 //}
     63 void Vector::reset(double n1, double n2, Mode form)
     64 {
     65     mode = form;
     66     if (form == RECT)
     67     {
     68         x = n1;    //将传入的直角坐标系的参数传递给类中的成员变量x和y
     69         y = n2;
     70         set_mag(); //设置x和y对应的极坐标系中的值
     71         set_ang();
     72     }
     73     else if (form == POL)
     74     {
     75         mag = n1;
     76         ang = n2 / rad_to_deg;  //将度数转换为弧度制
     77         set_x();
     78         set_y();
     79     }
     80     else
     81     {
     82         cout << "您输入有误,将坐标系的值全部设置为0" << endl;
     83         x = y = mag = ang = 0;
     84     }
     85 }
     86 
     87 //设置极坐标系的长度函数
     88 void Vector::set_mag()
     89 {
     90     mag = sqrt(x * x + y * y);
     91 }
     92 void Vector::set_ang()
     93 {
     94     ang = atan2(y, x);  //返回(x,y)的正切值
     95 }
     96 void Vector::set_x()
     97 {
     98     x = mag * cos(ang);
     99 }
    100 void Vector::set_y()
    101 {
    102     y = mag * sin(ang);
    103 }
    104 
    105 //直角坐标系或者是极坐标系模式的选择
    106 void Vector::polar_mode()
    107 {
    108     mode = POL;
    109 }
    110 void Vector::rect_mode()
    111 {
    112     mode = RECT;
    113 }
    114 
    115 //运算符重载
    116 Vector Vector::operator+(const Vector & b) const
    117 {
    118     //Vector V;  //新建一个类对象,作为返回值
    119     //V.x = x + b.x;  //自己的想法
    120 
    121     return Vector(x + b.x, y + b.y);  //调用构造函数,模式选择为默认值RECT
    122     //不用去别另外的一个模式,因为在主函数中即使是用RECT模式去减
    123     //接下来,RECT模式也会转换为POL模式中的参数的
    124     //x和y的值为调用operator+()对象中的数据,b.x为作为实参传入的对象中的数据
    125     
    126 }
    127 Vector Vector::operator-(const Vector & b) const
    128 {
    129     return Vector(x - b.x, y - b.y); //调用构造函数,模式选择为默认值RECT
    130     //x和y的值为调用operator-()对象中的数据,b.x为作为实参传入的对象中的数据
    131 }
    132 Vector Vector::operator-() const
    133 {
    134     return Vector(-x, -y);
    135     //x和y的值为调用operator-()对象中的数据
    136 }
    137 Vector Vector::operator*(double n) const
    138 {
    139     return Vector(x*n, y*n);
    140     //x和y的值为调用operator-()对象中的数据
    141 }
    142 
    143 //友元函数的声明
    144 //Vector operator*(double n, const Vector & b) //刚刚没有使用名称空间对operator*()声明,导致b.x出错
    145 //如果友元函数在名称空间中,必须要使用名称空间对友元函数的函数名进行声明,否则无法访问类中的数据
    146 //还有一个方法是在cpp文件中也将namespace VECTOR{...},按照h文件中的写法,照样搬过来就可以不用加VECTOR::
    147 Vector VECTOR::operator*(double n, const Vector & b)
    148 {
    149     return Vector(b.x * n , b.y * n);
    150     //return b * n;
    151 }
    152 std::ostream & VECTOR::operator<<(std::ostream & os, const Vector & v)
    153 {
    154     if (v.mode == Vector::RECT)
    155         os << "(x,y) = " << "(" << v.x << "," << v.y << ")
    ";
    156     else if (v.mode == Vector::POL)
    157         os << "(mag,ang) = " << "(" << v.mag << "," << v.ang * rad_to_deg << ")
    ";  //将rad转换为度数
    158     else
    159         os << "Vector object mode is invalid
    ";
    160     return os;
    161 }
    vect.cpp
     1 #include <iostream>
     2 #include <ctime>  //for time()
     3 #include <cstdlib> //for rand()、srand()
     4 #include"vect.h"
     5 
     6 int main()
     7 {
     8     using namespace std;
     9     using VECTOR::Vector;
    10 
    11     srand(time(0));
    12 
    13     Vector step;  //使用默认构造函数创建对象,该对象中的数据全部为0,默认为直角坐标系
    14     Vector result(0.0, 0.0);  //隐式的调用构造函数创建对象,并将该对象中的变量设置为0,默认为直角坐标系
    15     double direction = 0.0;  //走的方向
    16     double dstep = 0.0;  //每步走的长度
    17     double target = 0.0;  //要走的长度,该长度为极坐标系中的长度
    18     unsigned long steps = 0.0;  //定义走的总步数
    19 
    20     cout << "Enter target distance(任意子母键退出): ";
    21     while (cin >> target)
    22     {
    23         cout << "Enter step length: ";
    24         if (!(cin >> dstep))
    25         {
    26             break;  //如果输入的不是数字,那么退出while循环
    27         }
    28         //对象时不可以直接调用类中的私有变量的,只能调用公有函数!!
    29         while (result.magval() < target)
    30         {
    31             direction = rand() % 360;  //防止随机数大于360出现的情况
    32             step.reset(dstep, direction, Vector::POL); //重置step对象在的数据
    33             result = result + step;
    34             /*steps++;*/  //走的总步数
    35             cout << steps++ << endl;
    36             cout << result.magval() << endl;
    37         }
    38         cout << "After " << steps << " steps, 对象到达了如下坐标(直角坐标系):";
    39         cout << result << endl;  //输出对象result中的数据,默认result对象的模式为RECT(直角坐标系)
    40         result.polar_mode();  //设置result对象的模式为极坐标系POL
    41         cout << "或者在极坐标系下的坐标为:" << endl;
    42         cout << result << endl;  //极坐标系下输出
    43 
    44         cout << "平均每步走的距离为:" << result.magval() / steps << endl;
    45 
    46         //重置变量,为下一次循环做准备
    47         steps = 0;
    48         result.reset(0.0, 0.0);
    49         cout << "Enter target distance(任意子母键退出): ";
    50     }
    51 
    52     cout << "Bye!
    ";
    53     cin.clear();  
    54     while (cin.get() != '
    ')
    55         continue;
    56     system("pause");
    57     return 0;
    58 }
    user_main.cpp

     将double、int等数据类型赋值给类对象  

    01)以前声明对象并使用构造函数对其进行初始化的方法
     Stonewt blossem(132.5); //使用一个参数的构造函数对对象blossem进行初始化
     Stonewt blossem = Stonewt(132.5); //显式的调用构造函数对类对象进行初始化
     Stonewt buttercup(10, 2); //使用两个参数的构造函数对对象buttercup进行初始化
     Stonewt bubbles; //使用默认构造函数对bubbles进行初始化
    02)如果一个参数的构造函数创建了类对象,那么该对象可以接受一个double型、int型等数据类型对其进行赋值,如:
     Stonewt myCat; //声明一个对象
     myCat = 19.6; //使用一个数对类对象进行赋值,前提是该类中得有只有一个形参的构造函数
     //以上代码使用Stonewt(double lbs)创建一个类对象,并将19.6作为初始值。这一过程是自动进行的,即隐式的
    03)使用explicit来声明只有一个形参的构造函数,目的是防止意外的类型转换。如:
     explicit Stonewt(double lbs); //这将关闭上边的隐式转换

     Stonewt myCat;
     myCat = 19.6; //此时是不合法的,因为使用了关键字explicit声明只有一个形参的构造函数
     myCat = Stonewt(19.6); //合法,显式的进行类型强制转换
     myCat = Stonewt(7000); //合法,先将7000转换为double类型,然后进行强制转换
     myCat = (Stonewt)19.6; //合法,老式的方法
    04)如果使用了关键字explicit声明构造函数,那么该构造函数就只能用来进行显式强制转换
    05)如果类方法中定义了一个下面的带一个参数的构造函数:
     Stonewt(double lbs);
     那么再定义一个下面的只带一个参数的构造函数是不允许的:
     Stonewt(long lbs);

     1 #ifndef STONEWT_H_
     2 #define STONEWT_H_
     3 
     4 class Stonewt
     5 {
     6 private:
     7     enum { Lbs_per_Stn = 14 };  //用枚举的方法定义一个常量,14后面不用加分号
     8     int stone;
     9     double pds_left;
    10     double pounds;
    11 public:
    12     Stonewt(double lbs);  //声明一个参数的构造函数
    13     Stonewt(int stn, double lbs);   //声明两个参数的构造函数
    14     Stonewt();  //声明默认构造函数
    15     ~Stonewt();  //声明析构函数
    16     void show_lbs() const;
    17     void show_stn() const;
    18 };
    19 
    20 #endif
    21 
    22 /* 将double、int等数据类型赋值给类对象 */
    23 /*
    24 01)以前声明对象并使用构造函数对其进行初始化的方法:
    25    Stonewt blossem(132.5);  //使用一个参数的构造函数对对象blossem进行初始化
    26    Stonewt blossem = Stonewt(132.5);  //显式的调用构造函数对类对象进行初始化
    27    Stonewt buttercup(10, 2);  //使用两个参数的构造函数对对象buttercup进行初始化
    28    Stonewt bubbles;  //使用默认构造函数对bubbles进行初始化
    29 02)如果一个参数的构造函数创建了类对象,那么该对象可以接受一个double型、int型等数据类型对其进行赋值,如:
    30    Stonewt myCat;  //声明一个对象
    31    myCat = 19.6;  //使用一个数对类对象进行赋值,前提是该类中得有只有一个形参的构造函数
    32    //以上代码使用Stonewt(double lbs)创建一个类对象,并将19.6作为初始值。这一过程是自动进行的,即隐式的
    33 03)使用explicit来声明只有一个形参的构造函数,目的是防止意外的类型转换。如:
    34    explicit Stonewt(double lbs);  //这将关闭上边的隐式转换
    35 
    36    Stonewt myCat;
    37    myCat = 19.6;  //此时是不合法的,因为使用了关键字explicit声明只有一个形参的构造函数
    38    myCat = Stonewt(19.6);  //合法,显式的进行类型强制转换
    39    myCat = Stonewt(7000);  //合法,先将7000转换为double类型,然后进行强制转换
    40    myCat = (Stonewt)19.6;  //合法,老式的方法
    41 04)如果使用了关键字explicit声明构造函数,那么该构造函数就只能用来进行显式强制转换
    42 05)如果类方法中定义了一个下面的带一个参数的构造函数:
    43    Stonewt(double lbs);
    44    那么再定义一个下面的只带一个参数的构造函数是不允许的:
    45    Stonewt(long lbs);
    46 05)
    47 
    48 */
    stonewt.h
     1 //stonewt.cpp
     2 #include <iostream>
     3 #include "stonewt.h"
     4 
     5 using std::cout;
     6 using std::endl;
     7 
     8 //接受一个参数的构造函数
     9 //可以使用数字对类对象进行初始化,即:
    10 //Stonewt myCat;  
    11 //myCat=19.6;  //该句表明,上句是使用只有一个形参的构造函数创建的对象
    12 Stonewt::Stonewt(double lbs)
    13 {
    14     stone = int(lbs) / Lbs_per_Stn;
    15     pds_left = int(lbs) % Lbs_per_Stn;
    16     pounds = lbs;
    17 }
    18 
    19 //接受一个参数的构造函数(使用关键字explicit)
    20 //可以使用数字对类对象进行初始化,即:
    21 //Stonewt myCat = Stonewt(19.6);  //使用关键字explicit之后,就只能只有初始化对象 
    22 /*explicit Stonewt::Stonewt(double lbs)
    23 {
    24     stone = int(lbs) / Lbs_per_Stn;
    25     pds_left = int(lbs) % Lbs_per_Stn;
    26     pounds = lbs;
    27 }*/
    28 
    29 //接受两个参数的构造函数
    30 Stonewt::Stonewt(int stn, double lbs)
    31 {
    32     stone = stn;
    33     pds_left = lbs;
    34     pounds = stn * Lbs_per_Stn + lbs;
    35 }
    36 
    37 //默认构造函数
    38 Stonewt::Stonewt()
    39 {
    40     stone = pounds = pds_left = 0;
    41 }
    42 
    43 //析构函数
    44 Stonewt::~Stonewt()
    45 {
    46 
    47 }
    48 
    49 //普通类方法
    50 void Stonewt::show_stn() const
    51 {
    52     cout << stone << " stone, " << pds_left << " pounds" << endl;
    53 }
    54 void Stonewt::show_lbs() const
    55 {
    56     cout << pounds << " pounds" << endl;
    57 }
    stonewt.cpp
     1 //user_main,cpp
     2 #include <iostream>
     3 #include "stonewt.h"
     4 
     5 using std::cout;
     6 using std::endl;
     7 
     8 void display(const Stonewt & st, int n);//第一个形参可以接受Stonewt对象或者是数字都可以
     9 //如果第一个形参接受的实参为一个数字,在这里也是允许的,即:
    10 // Stonewt & st = 422;  类似于Stonewt st=422; //使用接受一个参数的构造函数对st进行初始化
    11 
    12 int main()
    13 {
    14     Stonewt incognito = 275;  //先对275转换成double型,然后再用接受一个参数的构造函数对类对象进行初始化
    15     //Stonewt(double lbs)即lbs=275
    16     Stonewt wolfe(285.7);  //以前初始化对象的方法,等价于Stonewt wolfe = 285.7;
    17     Stonewt taft(21, 8);  //使用接受两个参数的构造函数对类对象进行初始化
    18     //Stonewt(int stn, double lbs)即stn=21,lbs=8
    19 
    20     cout << "The celebrity weighted ";
    21     incognito.show_stn();
    22 
    23     cout << "The detective weighted ";
    24     wolfe.show_stn();
    25 
    26     cout << "The president weighted ";
    27     taft.show_stn();
    28 
    29     incognito = 276.8;  //同样是调用Stonewt(double lbs)构造函数,对类对象进行重新初始化
    30     taft = 325;  //调用Stonewt(double lbs)构造函数,对类对象taft进行重新初始化,虽然他taft不是使用接受一个参数的构造函数创建的
    31 
    32     display(taft, 2);  //display()第一个形参指向taft对象
    33     display(422, 2);  //display()第一个实参为数字,也是可以的,只是在类对象初始化是可以的
    34 
    35 
    36     system("pause");
    37     return 0;
    38 }
    39 
    40 void display(const Stonewt & st, int n)
    41 {
    42     for (int i = 0; i < n; i++)
    43     {
    44         cout << "Wow! ";
    45         st.show_stn();
    46     }
    47 }
    48 
    49 /* 总结 */
    50 /*
    51 01)如果类中有只有一个参数的构造函数,那么下面的引用的用法是可以的
    52    Stonewt & st = 422;  //类似于Stonewt st=422; 使用接受一个参数的构造函数对st进行初始化
    53    编译器会将该数字(422)通过Stonewt(double lbs)构造函数,编程Stonewt对象,然后 再赋给引用st
    54 02)类对象使用数字对其进行初始化了之后,允许以后再次使用数字对其进行初始化,如下:
    55    incognito = 276.8;
    56 */
    user_main.cpp

    /* 总结 */
    01)如果类中有只有一个参数的构造函数,那么下面的引用的用法是可以的
         Stonewt & st = 422; //类似于Stonewt st=422; 使用接受一个参数的构造函数对st进行初始化
         编译器会将该数字(422)通过Stonewt(double lbs)构造函数,编程Stonewt对象,然后 再赋给引用st
    02)类对象使用数字对其进行初始化了之后,允许以后再次使用数字对其进行初始化,如下:
         incognito = 276.8;

     将类对象赋值给double、int等型的变量  m8

    01)问题的提出:
      上一节中提到了可以将double、int型的数据赋值给类对象,那么反过来呢?
      即:Stonewt wolfe(285.7);
      double host = wolfe; //这样也是可以的,只不过得在类中声明转换函数
    02)转换函数的声明方法:
     operator typeName(); //typeName为要转换成的数据类型,如double、int等
     如:operator double(); //声明由类对象转换成double型数据的类方法
     注意以下几点:
       A 转换函数是类方法
       B 转换函数不能指定返回类型且没有任何的参数
    03)转换函数的定义方法:(由于转换函数是类方法,所以在定义时必须使用类限定符Stonewt::)
     Stonewt::operator double()
      { return pounds;} //一般是在函数体中返回一直类中的私有变量
    04)转换函数的使用方法:
     Stonewt wolfe(285.7);
     double host = wolfe; //隐式的调用转换函数 
     double host = double(wolfe) //显式的调用转换函数
     需要注意的是,如果定义了多个转换函数:
     operator int(); //#1
     operator double(); //#2
     隐式的调用转换函数是不合法的,因为编译器不知道是调用#1还是调用#2,从而产生二义性,产生报错
    05)原则上说最好使用显式转换,为此,C++提供了关键字explicit用于转换函数,如:
     explicit operator double(); //不能使用隐式的调用该函数,必须使用显式的转换方法
     explicit operator int(); //同理
     即:
     Stonewt wolfe(285.7);
     double host = wolfe; //如果转换函数前加了关键字explicit,隐式的调用转换函数是不合法的
     double host = double(wolfe) //显式的调用转换函数,合法
     定义的时候使用如下方法:
     explicit Stonewt::operator int()  //注意explicit的位置
     { return pounds; }
    06)除了使用转换函数,我们也可以使用类方法去实现将类对象赋值给常规变量
     即下面两种方法是等价的:
     explicit Stonewt::operator int() //定义转换函数实现将类对象赋值给常规变量
     { return pounds; }

     double Stonewt::Stone_to_double() //定义方法实现将类对象赋值给常规变量
     { return double(pounds);}

     第一种方法的调用方法是:
     Stonewt wolfe(285.7);
     double host = double(wolfe) //显式的调用转换函数,合法

     第二种方法的调用方法是:
     Stonewt wolfe(285.7);
     double wo = wolfe.Stone_to_double(); //类对象wolfe调用类方法Stone_to_double()

  • 相关阅读:
    vue框架组件id获取
    Proxy 与 Object.defineProperty 优劣对比
    vue 父组件监听子组件生命周期
    Vue 的父组件和子组件生命周期钩子函数执行顺序
    k8s 集群部署--学习
    Linux命令:ipcs/ipcrm命令
    Python模块
    XAMPP+TestLink
    bug管理工具
    批量管理工具:pssh/ansible
  • 原文地址:https://www.cnblogs.com/YiYA-blog/p/10694292.html
Copyright © 2020-2023  润新知