C++类的自动转换和强制转换详解和实现

分为三种情况:

(1)如果要进行的转换之间是兼容的,C++自动将值转换为接收变量的类型:

如:

[cpp]  view plain  copy
  1. int count = 8.8;  
  2.   double time= 3;  
  3.   long day = 8;  

在C++看来这些都是合法的,因为他们表示的本质是一样的:数字,而且C++包含了用于进行转换的内置规则。然而可能会降低精度。


(2):C++不自动转换不兼容的类型:

如      int * pr = 10;

这种语句是非法的,因为左边是指针,但是右边却是数字。


(3)强制类型转换:

 如: int *pr = (int *) 10;

这条语句通过类型的强制转换的结果是这条语句可以正常进行。表示:定义一个地址为10 的指针。(这种赋值是没有什么意义的);


C++如何处理用户自定义的类型:

1.将别的转换为类对象:

将类定义成与基本类型相关或者是与另一个类相关,使得从一个类到另一个类的转换时有意义的。在这种情况下可以指示C++如何进行自动类型转换,或者通过强制类型转换来完成:

下面我们通过一个例子来详细介绍:

需求:计量单位磅转换为英石:


[cpp]  view plain  copy
  1. Stone.h文件:  
  2. #pragma once  
  3. #ifndef STONEWT_H_  
  4. #define STONEWT_H_  
  5.   
  6. class CStonewt  
  7. {  
  8. private:  
  9.     enum{Lbs_per_stn = 14};  
  10.     int m_stone;  
  11.     double m_pds_left;  
  12.     double m_pounds;  
  13.   
  14. public:  
  15.     CStonewt();  
  16.     CStonewt(double lbs);  
  17.     CStonewt(int stn, double lbs);  
  18.   
  19.     ~CStonewt();  
  20.     void Show_lbs() const;  
  21.     void Show_stn() const;  
  22. };  
  23. #endif;  
  24.   
  25. Stone.cpp文件:  
  26. #include "stdafx.h"  
  27. #include "Stonewt.h"  
  28. #include  
  29. using std::cout;  
  30.   
  31. CStonewt::CStonewt(double lbs)                 //构造函数  
  32. {  
  33.     m_stone = int(lbs) / Lbs_per_stn;  
  34.     m_pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);  
  35.     m_pounds = lbs;  
  36. }  
  37.   
  38. CStonewt::CStonewt()                           //构造函数  
  39. {  
  40.     m_stone = m_pounds = m_pds_left = 0;  
  41. }  
  42.   
  43. CStonewt::CStonewt(int stn, double lbs)         //构造函数  
  44. {  
  45.     m_stone = stn;  
  46.     m_pds_left = lbs;  
  47.     m_pounds = stn *Lbs_per_stn + lbs;  
  48. }  
  49. CStonewt::~CStonewt()  
  50. {  
  51. }  
  52.   
  53. void CStonewt::Show_lbs() const  
  54. {  
  55.     cout << m_pounds << "pounds\n";  
  56. }  
  57. void CStonewt::Show_stn() const  
  58. {  
  59.     cout << m_stone << "stone," << m_pds_left << "pounds\n";  
  60. }  
  61. Main'程序:  
  62. #include "stdafx.h"  
  63. #include   
  64. #include "Stonewt.h"  
  65.   
  66. using std::cout;  
  67. void Display(const CStonewt & st, int n);  
  68. int _tmain(int argc, _TCHAR* argv[])  
  69. {  
  70.   
  71.     CStonewt incognito = 275;  
  72.     CStonewt wolfe(285.7);  
  73.     CStonewt taft(21, 8);  
  74.       
  75.     cout << "the Celebrity weighed";  
  76.     incognito.Show_stn();  
  77.     cout << "The detective weighted";  
  78.     taft.Show_lbs();  
  79.     incognito = 276.8;  
  80.     taft = 325;  
  81.     cout << "After dinner ,the celebrity weighted";  
  82.     incognito.Show_stn();  
  83.     cout << "After dinner, the Pressident weighted";  
  84.     taft.Show_lbs();  
  85.     Display(taft, 2);  
  86.     cout << "The wrestler weighed even more.\n";  
  87.     Display(422, 2);  
  88.     cout << "No stone left unearned.\n";  
  89.   
  90.     return 0;  
  91. }  
  92. void Display(const CStonewt &st, int n)  
  93. {  
  94.     int i;  
  95.     for (i = 0; i < n; i++)  
  96.     {  
  97.         cout << "WOW!";  
  98.         st.Show_stn();  
  99.     }  
  100. }  

Stonewt类有三个构造函数,可以允许将Stonewt对象初始化为一个浮点数或者两个浮点数,也可以不进行初始化。


隐式的自动类型转换:

下面我们先来看一下这个构造函数:

CStonewt(double lbs);

这个构造函数允许将double类型的值转化为Stonewt类型

eg: CStonewt myCat;

      myCat = 19.6;


原理:程序使用CStonewt(double lbs),来创建一个临时的Stonewt对象,然后将19.6赋值给它,随后,采用逐成员赋值的方式将该对象的内容赋值到myCat中,这一过程成为隐式转换,因为他是自动进行的。而不需要显示强制类型转换。

只有接受一个参数的构造函数才能作为转换函数,例如:CStonewt(int stn,double lbs);不能作为转换类型。但是如果给第二哥参数提供默认值,它遍可以转换int:

CStonewt(int stn,double lbs = 0);


显式类型强制转换:

将构造函数用作自动类型转换函数似乎是一种非常好的特性,但是这种自动类型转换并不是总是合乎需要的,因为这可能导致意外的类型转换:

解决方法:C++新增了 关键字explicit用于关闭这种自动特性,也就是说可以这样声明构造函数:

explicit CStonewt(double  lbs);

这将关闭隐式类型转换,单仍然允许显示类型转换,即显式类型转换:

CStonewt myCat;

 my Cat = 19.6  (这种方式是错的)

myCat = CStonewt(19.6)( 允许的)

myCat = (CStonewt)19.6 (允许的)


那么问题来了,编译器都在什么时候调用CStonewt(double lbs)函数呢?(如果声明为explict,则只能显式类型转换,不支持以下几点):

1.将CStonewt对象初始化为double值时;

2.将double值传递给接受CStonewt参数的函数时;

3.返回值被声明为CStonewt得到函数试图返回double值时;

4.将double值赋给CStonewt对象时;

5.在上述任一一种情况下,使用可转换为double类型的内置类型时;

最重要的一点:

函数原型化提供的参数匹配过程中,允许使用CStonewt(double)构造函数来转换其他数值类型。

eg:

Cstonewt  Jumb(7000);

Jumb = 7300;


这两条语句都是先将int 转化为double,然后使用CStonewt(double)构造函数。然而这是有前提性的:

即不存在二义性。如果存在CStonewt(long), 

则编译器将拒绝执行这些语句,因为int可以转为long 或者double,一次调用会出现二义性..、


将类类型转换为别的类型:

构造函数只用于从某种类型到类类型的转换,要进行相应的反转,必须使用特殊的C++运算符函数--转换函数

转换函数是永辉自定义的强制类型转换,可以像使用强制类型转换那样使用它们。


eg:

[cpp]  view plain  copy
  1. CStonewt wolfe =(285.7);  
  2. double host = double ((wolfe);  
  3. double thinker = (double) wolfe;  

如何创建转换函数:

operator typeName ();

注意点:

转换函数必须是类方法

转换函数不能指定返回类型

转换函数不能有参数

接着上个程序接着说:


如果现在我想让CStonewt类型转化为double类型,要怎么做呢?

1.在CStonewt的.h文件中声明类方法:

[cpp]  view plain  copy
  1. operator double () const;  
  2. operator int () const;  

然后在cpp文件中完成定义:

[cpp]  view plain  copy
  1. Cstonewt::operator int() const  
  2. {  
  3.   erturn pounds;  
  4. }  
  5. CStonewt::operator double () const  
  6. {  
  7.   cout << int(pounds + 0.5);  
  8. }  

此时,我们就可以在main函数中将CStonewt赋值给int、double 了; 

[cpp]  view plain  copy
  1. CStonewt  popins(9,2.8);  
  2. double p_wt = popins;  
  3. cout <<(int) popinns<


我们首先来分析一下以上几个语句:
首先定义popons对象,将其赋值给一个double 变量。

输出时要注意将其强行转换一下, 如果我们直接输出popins,那么编译器不知道该将其转换为int 还是double后输出。

(因为我们没有重载CStonewt的输出)


还有一种情况需要注意:

long temp = popins; 这条语句是不正确的,因为存在二义性,因为int、double都可以转换为long 类型。如果删除一个int或者double的转换函数,则这条语句将可以执行。。


缺点:

跟构造函数一样,转换函数提供执行自动、隐式转换的函数所存在的问题是:

在用户 不希望转换的 时候转换函数也可能进行转换。

总结:

1.要谨慎的使用隐式转换函数,通常最好的选择是仅在被显示的调用时才会执行。


2.只有一个参数的类构造函数将用于类型与该参数相同的值转换为类类型。

例如:将int类型转换为CStonewt对象是,接受int 参数的CStonewt类构造函数将自动被调用,然而在构造函数声明中使用explicit可防止隐式转换,而只允许显式转换。


3.被称为转换函数的特殊类成员运算符函数,用于将类对象转换为其他类型。

转换函数是类成员,没有返回类型,没有参数名为 operator typeName();

其中 typeName是对象将被转换为的类型,将类对象赋给typeName变量或者将其强制转换为typeName

类型时,该转换函数将会被自动调用。


4.尤其要注意过多的转换函数将导致出现二义性的几率变大,要谨慎防止二义性的出现。

你可能感兴趣的:(c++,自定义转换)