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()

原文地址:https://www.cnblogs.com/YiYA-blog/p/10694292.html