类型转换

将一个标准类型变量的值赋值给另一种标准类型的变量时,如果这两种类型兼容,则C++自动将这个值转换为接收变量的类型。

long count = 8; //int类型转换为long类型
double time = 11; //int类型转换为double类型
int side = 3.33; //double类型转换为int类型

在C++各种数值类型都表示相同的东西,一个数字,同时C++包含用于进行转换的内置规则。

C++语言不自动转换不兼容的类型:

int *p = 10; //错误

左边是指针类型,右边是数字。

在无法自动转换时,可以使用强制类型转换:

int *p = (int *) 10; //可行,p和(int *)10都是指针

将10强制转换为int指针类型,将指针设置为地址10。

磅转换英石

磅转换为英石,用一种类型转换为另一种类型的方式。

stonewt.h

#ifndef STONEWT_H_
#define STONEWT_H_class Stonewt
{private:enum {Lbs_per_stn = 14}; //每英石的磅值int stone; //总英石值double pds_left; //英石double pounds; //总磅值
public:Stonewt(double lbs); //磅值的构造函数Stonewt(int stn, double lbs); //英石的构造函数Stonewt(); //默认构造函数~Stonewt(); //void show_lbs() const; //以磅值显示void show_stn() const; //以英石显示
};
#endif

对于定义类特定的常量来说,如果它们是整数,enum提供一种方便的途径。

static const int Lbs_per_stn = 14;

这个类并非真的需要声明构造函数,,因为自动生成的more构造函数就很好。提供显示声明可防止必须定义构造函数。

stonewt.cpp

#include "stonewt.h"
#include <iostream>
using namespace std;Stonewt::Stonewt(double lbs)
{stone = int(lbs) / Lbs_per_stn; //整数除法pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);pounds = lbs;
}Stonewt::Stonewt(int stn, double lbs)
{stone = stn;pds_left = lbs;pounds = stn * Lbs_per_stn + lbs;
}Stonewt::Stonewt() //默认构造函数
{stone = pounds = pds_left = 0;
}Stonewt::~Stonewt() //析构函数
{}//以英石和磅为单位显示
void Stonewt::show_stn() const
{cout << stone << " stone, " << pds_left << " pounds\n";
}//以磅为单位显示
void Stonewt::show_lbs() const
{cout << pounds << " pounds\n";
}

在C++中,接受一个参数的构造函数为将类型与该参数相同的值转换为类提供了蓝图。下面的构造函数用于将double类型的值转换为Stonewt类型。

Stonewt(double lbs); //double转Stonewt

也就是可以这样编写

Stonewt myCat;
myCat = 19.6;

程序将使用构造函数Stonewt(double)来创建一个临时的Stonewt对象,并将19.6作为初始化值。随后,采用逐成员赋值方式将该临时对象的内容复制到myCat中。这过程称为隐式转换,因为它是自动进行的,而不需要显式强制类型转换。

只有接受一个参数的构造函数才能作为转换函数。

构造函数有两个参数,不能用来转换类型:

Stonewt(int stn, double lbs); //不能实现转换功能

然而,如果给第二个参数提供默认值,它便可用于转换int。

Stonewt(int stn, double lbs = 0); //int转换为Stonewt

构造函数用作自动类型转换函数可能会导致意外的类型转换。explicit可以关闭这种自动特性。

explicit Stonewt(double lbs); //不允许隐式转换

这将关闭上述示例中介绍的隐式转换,只能显式强制类型转换:

Stonewt myCat; //创建一个Stonewt对象
myCat = 19.6; //错误的,必须为显式
myCat = Stonewt(19.6); //正确,显式转换
myCat = (Stonewt)19.6; //正确,旧版本显示转换

注意:只接受一个参数的构造函数定义了从参数类型到类类型的转换。如果使用关键字explicit限定了这种构造函数,则它只能用于显示转换。

编译器在什么时候将使用Stonewt(double)函数
● 将Stonewt对象初始化为double值时。
● 将double值赋给Stonewt对象时。
● 将double值传递给接受Stonewt参数的函数时。
● 返回值被声明为Stonewt的函数试图返回double值时。
● 在上述任意一种情况下,使用可转换为double类型的内置类型时。

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

Stonewt Jumbo(7000); //使用Stonewt(double),int转换为double
Jumbo = 7300; 使用Stonewt(double),int转换为double

将int转换为double,然后使用Stonewt(double)构造函数。

main.cpp

#include <iostream>
#include "stonewt.h"
using namespace std;void display(const Stonewt &st, int n);int main()
{Stonewt incognito = 275; //构造函数初始化Stonewt wolfe(285.7); //Stonewt wolfe = 285.7Stonewt taft(21, 8);cout << "The celebrity weighted ";incognito.show_stn();cout << "The detective weighted ";wolfe.show_stn();cout << "The President weighted ";taft.show_lbs();incognito = 276.8; //利用构造函数转换taft = 325; //taft = Stonewt(325)cout << "After dinner, the celecbrity weighed ";incognito.show_stn();cout << "After dinner, the President weighed ";taft.show_lbs();display(taft, 2);cout << "The wrestler weighed even more.\n";display(422, 2);cout << "No stone left unearned\n";return 0;
}void display(const Stonewt & st, int n)
{for (int i = 0; i < n; i++){cout << "Wow! ";st.show_stn();}
}

构造函数只接受一个参数时。

Stonewt incognito = 275;

等价于另外两种格式

Stonewt incognito(275);
Stonewt incognito = Stonewt(275);

这两个格式可用于接受多个参数的构造函数。

接下来。

incognito = 276.8;
taft = 325;

第一条赋值语句使用接受double参数的构造函数,将276.8转换为一个Stonewt值,这将把incognito的pound成员设置为276.8。因为该语句使用了构造函数,所以还将设置stone和pds_left成员。
第二句将一个int值转换为double类型,然后使用Stonewt(double)来设置全部3个成员。

最后。

display(422, 2);

display(),第一个参数应是Stonewt对象。遇到int参数时,编译器查找构造函数Stonewt(int),以便将该int转换为Stonewt类型。由于没有找到这样的构造函数,因此编译器寻找接受其他内置类型(int可以转换为这种类型)的构造函数。Stone(double)构造函数满足这种要求,因此编译器将int转换为double,然后使用Stonewt(double)将其转换为一个Stonewt对象。

转换函数

转换函数是用户定义的强制类型转换,可以像使用强制类型转换那样使用他们。

如果定义了从Stonewt到double的转换函数,就可以使用下面的转换。

Stonewt wolfe(285.7);
double host = double(wolfe);
double thinker = (double)wolfe;

也可以让编译器来决定如何做:

Stonewt wells(20, 3);
double star = wells;

编译器发现,右侧是Stonewt类型,而左侧是double类型,因此它将查看程序员是否定义了与此匹配的转换函数(如果没有找到这样的定义,编译器将生成错误消息,指出无法将Stonewt赋给double)。

创建转换函数:

operator typeName();

● 转换为typeName类型。
● 转换函数必须是类方法。
● 转换函数不能指定返回类型。
● 转换函数不能有参数。

转换为double类型的函数的原型:

operator double();

typeName指出了要转换成的类型,因此不需要指定返回类型。

转换函数是类方法意味着:它需要通过类对象来调用,从而告知函数要转换的值。因此,函数不需要参数。

要添加将stone_wt对象转换为int类型和double类型的函数,需要将下面的原型添加到类声明中:

operator int();
operator double();

stonewt1.h

#ifndef STONEWT1_H_
#define STONEWT1_H_class Stonewt
{private:enum { Lbs_per_stn = 14 }; //每英石的磅值int stone; //总英石值double pds_left; //英石double pounds; //总磅值
public:Stonewt(double lbs); //磅值的构造函数Stonewt(int stn, double lbs); //英石的构造函数Stonewt(); //默认构造函数~Stonewt(); //析构函数void show_lbs() const; //以磅值显示void show_stn() const; //以英石显示//转换函数operator int() const;operator double() const;
};
#endif

int转换将待转换的值四舍五入为最接近的整数,而不是去掉小数部分。

stonewt1.cpp

#include <iostream>
#include "stonewt1.h"
using namespace std;Stonewt::Stonewt(double lbs)
{stone = int(lbs) / Lbs_per_stn;pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);pounds = lbs;
}Stonewt::Stonewt(int stn, double lbs)
{stone = stn;pds_left = lbs;pounds = stn * Lbs_per_stn + lbs;
}Stonewt::Stonewt()
{stone = pounds = pds_left = 0;
}Stonewt::~Stonewt()
{}void Stonewt::show_stn() const
{cout << stone << " stone, " << pds_left << " pounds\n";
}void Stonewt::show_lbs() const
{cout << pounds << " pounds\n";
}Stonewt::operator int() const
{return int(pounds + 0.5);
}Stonewt::operator double() const
{return pounds;
}

转换函数虽然没有声明返回类型,也要返回所需的值。

main.cpp

#include <iostream>
#include "stonewt1.h"
using namespace std;int main()
{Stonewt poppins(9, 2.8); //9英石,2.8磅double p_wt = poppins; //隐式转换cout << "Convert to double => ";cout << "Poppins: " << p_wt << " pounds.\n";cout << "Convert to int => ";cout << "Poppins: " << int(poppins) << " pounds.\n";return 0;
}

显示了将Stonewt对象转换为double类型和int类型的结果。

自动应用类型转换

假设省略了显式强制类型转换:

cout << "Poppins: " << poppins << " pounds.\n";

程序就会像下面那样进行隐式转换吗?

double p_wt = poppins;

不会。poppins应被转换为double类型,但cout并没有指出应转换为int或者double类型,在缺少信息时,就会二义性转换。如果类只定义了double转换函数,即只有一种转换可能,不存在二义性。

下面这种情况也会存在二义性。

long gone = poppins; //二义性

int和double值都可以被赋值给long变量,所以编译器使用任意一个转换函数都是合法的。

当类定义了两种或者更多的转换时,用显式强制类型转换来指出要使用哪个转换函数。

long gone = (double)poppins; //double类型转换
long gone = int(poppins); //int类型转换

将poppins转换为一个double值,然后赋值操作将该double值转换为long类型。

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

int ar[20];
...
Stonewt temp(14, 4);
...
int Temp = 1;
...
cout << ar[temp] << "!\n"; //用temp代替了Temp

Stonewt类定义了一个operator int(),因此Stonewt对象temp将被转换为int200,并用作数组索引。

在C++98中,关键字explicit不能用于转换函数,但C++11消除了这种限制,可将转换运算符声明为显式。

class Stonewt
{...explicit operator int() const;explicit operator double() const;
};

有了这些声明后,需要强制转换时将调用这些运算符。

用一个功能相同的非转换函数替换该转换函数即可,但仅在被显式地调用时,该函数才会执行。

Stonewt::operator int() { return int(pounds + 0.5); }

替换为:

int plb = poppins;

这样,下面的语句将是非法的:

int plb = poppins; //非法

但如果确实需要这种转换:

int plb = poppins.Stone_to_Int();

警告:最好选择仅在被显式地调用时才会执行的函数。

C++为类提供了下面的类型转换:
● 只有一个参数的类构造函数用于将类型与该参数相同的值转换为类类型。例如,将int值赋给Stonewt对象时,接受int参数的Stonewt类构造函数将自动被调用。然而,在构造函数声明中使用explict可防止隐式转换,而只允许显示转换。
● 被称为转换函数的特殊类成员运算符函数,用于将类对象转换为其他类型。转换函数是类成员,没有返回类型、没有参数、名为operator typeName(),其中,typeName是对象将被转换成的类型。将类对象赋给typeName变量或将其强制转换为typeName类型时,该转换函数将自动调用。

转换函数和友元函数

Stonewt类重载加法运算符。
成员函数来实现加法:

Stonewt Stonewt::operator+(const Stonewt &st) const
{double pds = pounds + st.pounds;Stonewt sum(pds);return sum;
}

友元函数来实现加法:

Stonewt operator+(const Stonewt &st1, const Stonewt &st2)
{double pds = st1.pounds + st2.pounds;Stonewt sum(pds);return sum;
}

别忘了要提供方法定义或友元函数定义,但不能都提供。

Stonewt jennySt(9, 12);
Stonewt bennySt(12, 8);
Stonewt total;
total = jennySt + bennySt;

如果提供了Stonewt(double)构造函数:

Stonewt jennySt(9, 12);
double kennyD = 176.0;
Stonewt total;
total = jennySt + kennyD;

但只有友元函数才允许这样做:

Stonewt jennySt(9, 12);
double pennyD = 146.0;
Stonewt total;
total = pennyD + jennySt;

将每一种加法都转换为相应的函数调用。

首先:

total = jennySt + bennySt;

被转换为:

total = jennySt.operator+(bennySt); //成员函数

或:

total = operator+(jennySt, bennySt); //友元函数

成员函数是通过Stonewt对象调用的。

其次:

total = jennySt + kennyD;

被转换为:

total = jennySt.operator+(kennyD); //成员函数

或:

total = operator+(jennySt, kennyD); //友元函数

同样,成员函数也是通过Stonewt对象调用的。每个调用中都有一个参数(kennyD)是double类型的,因此将调用Stonewt(double)构造函数,将该参数转换为Stonewt对象。

如果定义了operator double()成员函数,将造成混乱,因为该函数将提供另一种解释方式。编译器不是将kennyD转换为double并执行Stonewt加法,而是将jennySt转换为double并执行double加法。过多的转换函数会导致二义性。

最后:

total = pennyD + jennySt;

被转换为:

total = operator+(pennyD, jennySt); //友元函数

其中,两个参数都是double类型,因此将调用构造函数Stonewt(double),将它们转换为Stonewt对象。

然而,不能调用成员函数将jennySt和peenyD相加。将加法语法转换为函数调用将类似如下:

total = pennyD.operator+(jennySt); //没有意义

因为只有类对象才可以调用成员函数。C++不会将pennyD转换为Stonewt对象。将对成员函数参数进行转换,而不是调用成员函数的对象。

实现加法时的选择

要将double量和Stonewt量相加,有两种选择。

第一种方式:定义为友元函数,让Stonewt(double)构造函数将double类型的参数转换为Stonewt类型的参数。

operator+(const Stonewt &, const Stonewt &);

第二种方式:将加法运算符重载为一个显式使用double类型参数的函数:

Stonewt operator+(double x); //成员函数
friend Stonewt operator+(double x, Stonewt &s);

下面的语句将与成员函数operator+(double x)完全匹配:

total = jennySt + kennyD;

而下面的语句将与友元函数operator+(double x, Stonewt &s)完全匹配:

total = pennyD + jennySt;

第一种方式(依赖于隐式转换)使程序更简短,因为定义的函数较少。需要完成的工作较少,出错的机会较小。但每次需要转换时,都将调用转换构造函数,这将增加时间和内存开销。

第二种方式(增加一个显式地匹配类型的函数)则正好相反。但它程序较长,需要完成的工作更多,运行速度较快。

类的自动转换和强制类型转换相关推荐

  1. php自动转换和强制转换,Java数据类型转换(自动转换和强制转换)

    数据类型的转换,分为自动转换和强制转换.自动转换是程序在执行过程中"悄然"进行的转换,不需要用户提前声明,一般是从位数低的类型向位数高的类型转换;强制类型转换则必须在代码中声明,转 ...

  2. Java数据类型转换(自动转换和强制转换)

    数据类型的转换,分为自动转换和强制转换.自动转换是程序在执行过程中"悄然"进行的转换,不需要用户提前声明,一般是从位数低的类型向位数高的类型转换:强制类型转换则必须在代码中声明,转 ...

  3. 类型转换(自动转换,强制转换)

    类型转换(自动转换,强制转换) 类型转换:由于Java是强类型语言,所以要进行有些运算的时候,需要用到类型转换 从低到高:byte,short,char-----int-----long----flo ...

  4. java整数能强转转字符,Java中数据类型默认转换和强制类型转换

    默认转换: a:由低到高一次为:(byte   short    char  )---int ---long ---float --- double b:注意:byte   short    char ...

  5. C++ 学习笔记之---类的自动转换

    参考自<C++ Primer Plus 6th Edition> 类的自动转换: 说明:    C++允许程序员指定类之间进行转换的方式(含基本类型) 站在类的角度看问题,姑且分为&quo ...

  6. Vue.JS项目输入框中使用v-model导致number类型值自动转换成string问题的解决方案

    老文章了,目前用el-input v-model.number就能解决 很简单的操作,不知道当初在做什么,下文请直接忽略- Vue.JS项目中v-model导致输入框中number类型值自动转换成st ...

  7. C语言开发笔记(一)自动转换和强制转换

    整型数据和实行数据之间可以进行运算,而且字符型数据可以和整型数据通用,所以整型.实型.字符型数据之间也是可以进行运算的,但在运算处理之前,不同类型的数据要事先转换成同一种数据类型.转换方法有两种:自动 ...

  8. java自动转换_java类型转换详解(自动转换和强制转换)

    自动转换 class Hello { public static void main(String[] args) { //自动转换 int a = 5; byte b = 6; int c = a ...

  9. php中自动转换、强制转换、其他数据类型和bool转换

    0x01 自动转换 运算过程需要的数据类型和提供的数据类型不一致,将数据类型转为自己需要的类型 <?phpheader('content-type:text/html;charset=utf-8 ...

最新文章

  1. R语言使用reshape2包的melt函数将dataframe从宽表到长表(Wide- to long-format)、如果没有指定行标识符号,则所有的字段都会放入variable变量中
  2. 宏基ec471g黑苹果_宏碁acer ec-471g 黑苹果配置教程
  3. iOS之LLVM编译流程和Clang插件开发集成
  4. Android Studio运行报错:无法访问XXX......请删除该文件或确保该文件位于正确的类路径子目录中
  5. 一看就会的 GitHub 骚操作,让你看上去像一位开源大佬
  6. [Ext JS6实战] Ext.XTemplate
  7. 魔方机器人之下位机编程---------舵机控制
  8. redis插槽(slot)分配详解(集群动态新增或删除结点)
  9. opencv学习十二(车牌识别)
  10. 用cisco服务器添加html,在接入服务器上配置基本 AAA
  11. 开源在线答题系统包含:在线考试,问卷调查,在线练题。架构为jdk7、spring4、spring-mvc4
  12. php编写网页实例,网页实例:怎么详细介绍用PHP来编写网页记数器
  13. 05——去哪儿(旅游网站首页开发)
  14. 企业微信支付功能怎么开通?
  15. Windows为什么越用越慢而Linux却不会?
  16. contains( )方法
  17. [计算机组成原理]2-6、算数移位、逻辑移位、循环移位
  18. ps无法存储为html,ps一直无法存储因为程序错误的解决方法
  19. 数学软件四大家族——Maple、MATLAB、MathCAD和Mathematica优缺点比较
  20. 出门问问AIGC SaaS平台亮相数贸会 赋能内容创作全流程

热门文章

  1. 华为ap配置_13、了解下POE交换机以及AP供电几种方式
  2. hive 建表_Hive建表和内外部表的使用
  3. java常用算法_五分钟记住Java常用的八种排序算法与代码实现
  4. 30岁学编程python_我30岁了,转行学编程可以吗? 排除法告诉你答案
  5. Failed to start LSB: start and stop MariaDB
  6. Python入门基础之条件判断、循环、dict和set
  7. netty 入门(一)
  8. 第七章部分例题最大乘积
  9. Window下JDK、Tomcat、eclipse安装与配置
  10. AES加密,解决了同步问题,和随机密钥和固定密钥,多端通信加密不一致解决办法...