深入讲解C++数据类型转换的相关函数的知识

C++数据类型转换以及转换构造函数
标准数据类型之间的转换

在C++中,某些不同类型数据之间可以自动转换,例如

  int i = 6;
  i = 7.5 + i;

编译系统对 7.5是作为double型数处理的,在求解表达式时,先将6转换成double型,然后与7.5相加,得到和为13.5,在向整型变量i赋值时,将13.5转换为整数13,然后赋给i。这种转换是由C++编译系统自动完成的,用户不需干预。这种转换称为隐式类型转换。

C++还提供显式类型转换,程序人员在程序中指定将一种指定的数据转换成另一指定的类型,其形式为:

  类型名(数据)

  int(89.5)

其作用是将89.5转换为整型数89。

以前我们接触的是标准类型之间的转换,现在用户自己定义了类,就提出了一个问题:一个自定义类的对象能否转换成标准类型? 一个类的对象能否转换成另外一个类的对象?譬如,能否将一个复数类数据转换成整数或双精度数?能否将Date类的对象转换成Time类的对象?

对于标准类型的转换,编译系统有章可循,知道怎样进行转换。而对于用户自己声明的类型,编译系统并不知道怎样进行转换。解决这个问题的关键是让编译系统知道怎样去进行这些转换,需要定义专门的函数来处理。
转换构造函数

转换构造函数(conversion constructor function) 的作用是将一个其他类型的数据转换成一个类的对象。这里回顾一下以前学习过的几种构造函数:
1) 默认构造函数。以Complex类为例,函数原型的形式为:

  Complex( ); //没有参数

2) 用于初始化的构造函数。函数原型的形式为:

  Complex(double r, double i); //形参表列中一般有两个以上参数

3) 用于复制对象的复制构造函数。函数原型的形式为:

  Complex (Complex &c); //形参是本类对象的引用

现在介绍一种新的构造函数——转换构造函数。

转换构造函数只有一个形参,如

  Complex(double r) {real=r;imag=0;}

其作用是将double型的参数r转换成Complex类的对象,将r作为复数的实部,虚部为0。用户可以根据需要定义转换构造函数,在函数体中告诉编译系统怎样去进行转换。

在类体中,可以有转换构造函数,也可以没有转换构造函数,视需要而定。以上几种构造函数可以同时出现在同一个类中,它们是构造函数的重载。编译系统会根据建立对象时给出的实参的个数与类型选择形参与之匹配的构造函数。

假如在Complex类中定义了上面的构造函数,在Complex类的作用域中有以下声明语句:

  Complex cl(3.5) ; //建立对象cl,由于只有一个参数,调用转换构造函数

建立Comptex类对象cl,其real(实部)的值为3.5,imag(虚部)的值为0。它的作用就是将double型常数转换成一个名为cl的Complex类对象。也可以用声明语句建立一 个无名的Complex类对象。如

  Complex(3.6) ;  //用声明语句建立一个无名的对象,合法,但无法使用它

可以在一个表达式中使用无名对象,如:

  cl =Complex(3.6);  //假设cl巳被定义为Complex类对象

建立一个无名的Complex类对象,其值为(3.6+0i),然后将此无名对象的值賦给cl,cl 在赋值后的值是(3.6+0i)。

如果已对运算符“+”进行了重载,使之能进行两个Complex类对象的相加,若在程序中有以下表达式:

  c = cl +2.5;

编译出错,因为不能用运算符“+”将一个Comptex类对象和一个浮点数相加。可以先将 2.5转换为Complex类无名对象,然后相加:

  c = cl + Complex (2.5);  //合法

请对比Complex(2.5)和int(2.5)。二者形式类似,int(2.5)是强制类型转换,将2.5转换为整数,int()是强制类型转换运算符。可以认为Complex(2.5)的作用也是强制类型 转换,将2.5转换为Complex类对象。

转换构造函数也是一种构造函数,它遵循构造函数的一般规则。通常把有一个参数的构造函数用作类型转换,所以,称为转换构造函数。其实,有一个参数的构造函数也可以不用作类型转换,如

  Complex (double r){ cout<<r; } //这种用法毫无意义,没有人会这样用

转换构造函数的函数体是根据需要由用户确定的,务必使其有实际意义。例如也可 以这样定义转换构造函数:

  Complex(double r){ real =0; imag = r; }

即实部为0,虚部为r。这并不违反语法,但没有人会这样做。应该符合习惯,合乎情理。

注意:转换构造函数只能有一个参数。如果有多个参数,就不是转换构造函数。原因是显然的,如果有多个参数的话,究竟是把哪个参数转换成Complex类的对象呢?

归纳起来,使用转换构造函数将一个指定的数据转换为类对象的方法如下:
1) 先声明一个类。

2) 在这个类中定义一个只有一个参数的构造函数,参数的类型是需要转换的类型,在函数体中指定转换的方法。

3) 在该类的作用域内可以用以下形式进行类型转换:
    类名(指定类型的数据)
就可以将指定类型的数据转换为此类的对象。
不仅可以将一个标准类型数据转换成类对象,也可以将另一个类的对象转换成转换构造函数所在的类对象。如可以将一个学生类对象转换为教师类对象,可以在Teacher类中写出下面的转换构造函数:

  Teacher(Student& s){ num=s.num;strcpy(name, s.name);sex=s.sex; }

但应注意,对象s中的num,name,sex必须是公用成员,否则不能被类外引用。

C++类型转换函数(类型转换运算符函数)
用转换构造函数可以将一个指定类型的数据转换为类的对象。但是不能反过来将一个类的对象转换为一个其他类型的数据(例如将一个Complex类对象转换成double类型数据)。

C++提供类型转换函数(type conversion function)来解决这个问题。类型转换函数的作用是将一个类的对象转换成另一类型的数据。如果已声明了一个Complex类,可以在Complex类中这样定义类型转换函数:

  operator double( )
  {
    return real;
  }

函数返回double型变量real的值。它的作用是将一个Complex类对象转换为一个double型数据,其值是Complex类中的数据成员real的值。请注意,函数名是operator double,这点是和运算符重载时的规律一致的(在定义运算符“+”的重载函数时,函数名是operator +)。

类型转换函数的一般形式为:

  operator 类型名( )
  {
    实现转换的语句
  }

在函数名前面不能指定函数类型,函数没有参数。其返回值的类型是由函数名中指定的类型名来确定的。类型转换函数只能作为成员函数,因为转换的主体是本类的对象。不能作为友元函数或普通函数。

从函数形式可以看到,它与运算符重载函数相似,都是用关键字operator开头,只是被重载的是类型名。double类型经过重载后,除了原有的含义外,还获得新的含义(将一个Complex类对象转换为double类型数据,并指定了转换方法)。这样,编译系统不仅能识别原有的double型数据,而且还会把Complex类对象作为double型数据处理。

那么程序中的Complex类对具有双重身份,既是Complex类对象,又可作为double类型数据。Complex类对象只有在需要时才进行转换,要根据表达式的上下文来决定。转换构造函数和类型转换运算符有一个共同的功能:当需要的时候,编译系统会自动调用这些函数,建立一个无名的临时对象(或临时变量)。

[例] 使用类型转换函数的简单例子。

#include <iostream>
using namespace std;
class Complex
{
public:
  Complex( ){real=0;imag=0;}
  Complex(double r,double i){real=r;imag=i;}
  operator double( ) {return real;} //类型转换函数
private:
  double real;
  double imag;
};
int main( )
{
  Complex c1(3,4),c2(5,-10),c3;
  double d;
  d=2.5+c1;//要求将一个double数据与Complex类数据相加
  cout<<d<<endl;
  return 0;
}

对程序的分析:
1) 如果在Complex类中没有定义类型转换函数operator double,程序编译将出错。因为不能实现double 型数据与Complex类对象的相加。现在,已定义了成员函数 operator double,就可以利用它将Complex类对象转换为double型数据。请注意,程序中不必显式地调用类型转换函数,它是自动被调用的,即隐式调用。在什么情况下调用类型转换函数呢?编译系统在处理表达式 2.5 +cl 时,发现运算符“+”的左侧是double型数据,而右侧是Complex类对象,又无运算符“+”重载函数,不能直接相加,编译系统发现有对double的重载函数,因此调用这个函数,返回一个double型数据,然后与2.5相加。

2) 如果在main函数中加一个语句:

  c3=c2;

请问此时编译系统是把c2按Complex类对象处理呢,还是按double型数据处理?由于赋值号两侧都是同一类的数据,是可以合法进行赋值的,没有必要把c2转换为double型数据。

3) 如果在Complex类中声明了重载运算符“+”函数作为友元函数:

  Complex operator+ (Complex c1,Complex c2)//定义运算符“+”重载函数
  {
    return Complex(c1.real+c2.real, c1.imag+c2.imag);
  }

若在main函数中有语句

  c3=c1+c2;

由于已对运算符“+”重载,使之能用于两个Complex类对象的相加,因此将c1和c2按Complex类对象处理,相加后赋值给同类对象c3。如果改为

  d=c1+c2; //d为double型变量

将c1与c2两个类对象相加,得到一个临时的Complex类对象,由于它不能赋值给double型变量,而又有对double的重载函数,于是调用此函数,把临时类对象转换为double数据,然后赋给d。

从前面的介绍可知,对类型的重载和对运算符的重载的概念和方法都是相似的,重载函数都使用关键字operator。因此,通常把类型转换函数也称为类型转换运算符函数,由于它也是重载函数,因此也称为类型转换运算符重载函数(或称强制类型转换运算符重载函数)。

假如程序中需要对一个Complex类对象和一个double型变量进行+,-,*,/等算术运算,以及关系运算和逻辑运算,如果不用类型转换函数,就要对多种运算符进行重载,以便能进行各种运算。这样,是十分麻烦的,工作量较大,程序显得冗长。如果用类型转换函数对double进行重载(使Complex类对象转换为double型数据),就不必对各种运算符进行重载,因为Complex类对象可以被自动地转换为double型数据,而标准类型的数据的运算,是可以使用系统提供的各种运算符的。

[例] 包含转换构造函数、运算符重载函数和类型转换函数的程序。先阅读以下程序,在这个程序中只包含转换构造函数和运算符重载函数。

#include <iostream>
using namespace std;
class Complex
{
public:
  Complex( ){real=0;imag=0;} //默认构造函数
  Complex(double r){real=r;imag=0;}//转换构造函数
  Complex(double r,double i){real=r;imag=i;}//实现初始化的构造函数
  friend Complex operator + (Complex c1,Complex c2); //重载运算符“+”的友元函数
  void display( );
private:
  double real;
  double imag;
};
Complex operator + (Complex c1,Complex c2)//定义运算符“+”重载函数
{
  return Complex(c1.real+c2.real, c1.imag+c2.imag);
}
void Complex::display( )
{
  cout<<"("<<real<<","<<imag<<"i)"<<endl;
}
int main( )
{
  Complex c1(3,4),c2(5,-10),c3;
  c3=c1+2.5; //复数与double数据相加
  c3.display( );
  return 0;
}

注意,在Visual C++ 6.0环境下运行时,需将第一行改为#include <iostream.h>,并删去第2行,否则编译不能通过。

对程序的分析:
1) 如果没有定义转换构造函数,则此程序编译出错。

2) 现在,在类Complex中定义了转换构造函数,并具体规定了怎样构成一个复数。由于已重载了算符“+”,在处理表达式c1+2.5时,编译系统把它解释为

  operator+(c1, 2.5)

由于2.5不是Complex类对象,系统先调用转换构造函数Complex(2.5),建立一个临时的Complex类对象,其值为(2.5+0i)。上面的函数调用相当于

  operator+(c1, Complex(2.5))

将c1与(2.5+0i) 相加,赋给c3。运行结果为

  (5.5+4i)

3) 如果把“c3=c1+2.5;”改为c3=2.5+c1; 程序可以通过编译和正常运行。过程与前相同。

从中得到一个重要结论,在已定义了相应的转换构造函数情况下,将运算符“+”函数重载为友元函数,在进行两个复数相加时,可以用交换律。

如果运算符函数重载为成员函数,它的第一个参数必须是本类的对象。当第一个操作数不是类对象时,不能将运算符函数重载为成员函数。如果将运算符“+”函数重载为类的成员函数,交换律不适用。

由于这个原因,一般情况下将双目运算符函数重载为友元函数。单目运算符则多重载为成员函数。

4) 如果一定要将运算符函数重载为成员函数,而第一个操作数又不是类对象时,只有一个办法能够解决,再重载一个运算符“+”函数,其第一个参数为double型。当然此函数只能是友元函数,函数原型为

  friend operator+(double, Complex &);

显然这样做不太方便,还是将双目运算符函数重载为友元函数方便些。

5) 在上面程序的基础上增加类型转换函数:

  operator double( ){return real;}

此时Complex类的公用部分为:

  public:
  Complex( ){real=0;imag=0;}
  Complex(double r){real=r;imag=0;} //转换构造函数
  Complex(double r,double i){real=r;imag=i;}
  operator double( ){return real;}//类型转换函数
  friend Complex operator+ (Complex c1,Complex c2); //重载运算符“+”
  void display( );

其余部分不变。程序在编译时出错,原因是出现二义性。

(0)

相关推荐

  • 常用python数据类型转换函数总结

    1.chr(i)chr()函数返回ASCII码对应的字符串. 复制代码 代码如下: >>> print chr(65)A>>> print chr(66) >>> print chr(65)+chr(66)AB 2.complex(real[,imaginary])complex()函数可把字符串或数字转换为复数. 复制代码 代码如下: >>> complex("2+1j")(2+1j)>>> c

  • C语言数据类型转换实例代码

    数据类型转换就是将数据(变量.表达式的结果)从一种类型转换到另一种类型.例如,为了保存小数你可以将int类型的变量转换为double类型. 数据类型转换的一般格式为: (type_name) expression type_name为要转换到的数据类型,expression为表达式.例如: (float) a; //把a转换为实型 (int)(x+y); //把x+y的结果转换为整型 (float) 100; //将一个常量转换为实型 [示例]将整数转换为浮点数: #include <stdio

  • 浅析php数据类型转换

    PHP 在变量定义中不需要(或不支持)明确的类型定义:变量类型是根据使用该变量的上下文所决定的.也就是说,如果把一个字符串值赋给变量 var,var 就成了一个字符串.如果又把一个整型值赋给 var,那它就成了一个整数. PHP 的自动类型转换的一个例子是加号"+".如果任何一个操作数是浮点数,则所有的操作数都被当成浮点数,结果也是浮点数.否则操作数会被解释为整数,结果也是整数.注意这并没有改变这些操作数本身的类型:改变的仅是这些操作数如何被求值以及表达式本身的类型. 类型强制转换允许

  • PHP学习笔记(三):数据类型转换与常量介绍

    一.PHP数据类型相互转换 1.强制转换 复制代码 代码如下: // bool,int,float,string,array,object,null bool settype ( mixed $var , string $type ) 1)会改变原变量的类型 复制代码 代码如下: $a= "123a"; // string settype($a, "int"); // 勿遗漏双引号 var_dump($a); 2)在赋值前定义,不改变原变量类型 复制代码 代码如下:

  • 浅谈C++的语句语法与强制数据类型转换

    一个程序包含一个或多个程序单位(每个程序单位构成一个程序文件).每一个程序单位由以下几个部分组成: 预处理命令.如#include命令和#define命令. 声明部分.例如对数据类型和函数的声明,以及对变量的定义. 函数.包括函数首部和函数体,在函数体中可以包含若干声明语句和执行语句. 如下面是一个完整的C++程序: #include <iostream>//预处理命令 using namespace std; //在函数之外的声明部分 int a=3; //在函数之外的声明部分 int ma

  • C#基础之数据类型转换

    int x; long y = 123456789101112; x = (int)y; Console.WriteLine(x); 输出结果: 我们知道long类型的取值范围是-9223372036854775805~+9223372036854775807:int类型的是:-2147483648~+2147483647 上面的代码中,由于long变量的值超过了int能容纳的最大值,造成了数据的丢失:像这样有可能造成数据丢失或引发异常的任何转换都需要执行显式转换(explicit); 相反的就

  • 浅析Java中对象的创建与对象的数据类型转换

    Java:对象创建和初始化过程 1.Java中的数据类型     Java中有3个数据类型:基本数据类型(在Java中,boolean.byte.short.int.long.char.float.double这八种是基本数据类型).引用类型和null类型.其中,引用类型包括类类型(含数组).接口类型.     下列语句声明了一些变量: int k ; A a; //a是A数据类型的对象变量名. B b1,b2,-,b10000;// 假定B是抽象类或接口. String s; 注意:从数据类型

  • 深入讲解C++数据类型转换的相关函数的知识

    C++数据类型转换以及转换构造函数 标准数据类型之间的转换 在C++中,某些不同类型数据之间可以自动转换,例如 int i = 6; i = 7.5 + i; 编译系统对 7.5是作为double型数处理的,在求解表达式时,先将6转换成double型,然后与7.5相加,得到和为13.5,在向整型变量i赋值时,将13.5转换为整数13,然后赋给i.这种转换是由C++编译系统自动完成的,用户不需干预.这种转换称为隐式类型转换. C++还提供显式类型转换,程序人员在程序中指定将一种指定的数据转换成另一

  • Python变量、数据类型、数据类型转换相关函数用法实例详解

    本文实例讲述了Python变量.数据类型.数据类型转换相关函数用法.分享给大家供大家参考,具体如下: python变量的使用不需要进行类型声明(类型名 变量名),给一个变量名赋什么值就是什么类型. 变量的赋值使用 = 说明:虽然python声明变量时没有一个类型来圈注,但它并不是弱类型语言,相反,它是一门强类型语言. 弱类型的语言的东西没有明显的类型,它能随着环境的不同自动变换类型: 而强类型则没这样的规定,不同类型间的操作有严格定义,只有相同类型的变量才能操作 为什么说 Python 是强类型

  • python3的数据类型及数据类型转换实例详解

    之前介绍过python开发工具Jupyter的使用,今天继续讲解python的数据类型,python中有整型.浮点型.字符串.布尔类型,我们重点介绍布尔类型的运算,以及不同数据类型之间的转换.使用Jupyter运行的时候有两个快捷键,Shift + Enter执行本单元,并且光标会移动到下一个单元:Ctrl + Enter是执行本单元,并且光标留在本单元. 在python的数据类型中,我们定义变量a = 1, 那么a是一个整型:定义变量b = 1.2,那么b就是一个浮点型,浮点型还有一种科学记数

  • C++实例讲解四种类型转换的使用

    目录 C++类型转换 C语言风格的转换 C++风格的类型转换 static_cast reinterpret_cast const_cast dynamic_cast 小结 C++类型转换 C语言风格的转换 C语言提供了自己的一套转换规则,有好处也有坏处. C语言的风格:(type_name)expression; C语言提供了隐式类型转换和显式类型转换.显式类型转换一般也叫做强转,隐式类型转换编译器完成,如果转换不了就报错. 而C语言类型转换的风格好处就是简单,缺陷比如转换的可视性差,显式类型

  • JAVA中string数据类型转换详解

    在JAVA中string是final类,提供字符串不可以修改,string类型在项目中经常使用,下面给大家介绍比较常用的string数据类型转换: String数据类型转换成long.int.double.float.boolean.char等七种数据类型 复制代码 代码如下: * 数据类型转换 * @author Administrator * */ public class 数据类型转换 { public static void main(String[] args) { String c=

  • Java数据类型转换详解

    一.基本数据类型阐述 Java语言提供了八种基本类型.六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型. [注]JAVA没有unsigned类型 (1). 整数:int,short,byte,long (2). 浮点型:float,double (3). 字符:char (4). 布尔:boolean 基本型别     大小         最小值            最大值 void boolean     -----         -----             

  • js 数据类型转换总结笔记

    javascript有如下数据类型的转换方法: 一,转换成数字 xxx*1.0 转换成字符串 xxx+"" 二,从一个值中提取另一种类型的值,并完成转换工作. .提取字符串中的整数:parseInt(); 例:parseInt("123zhang")的结果为123 .提取字符串中的浮点数:parseFloat(); 例:parseFloat("0.55zhang")的结果为0.55 .执行用字符串表示的一段javascript代码:eval();

  • 浅析C#数据类型转换的几种形式

    1.Convert.ToInt32(); //转换成32位的整数.2.变量.ToString();/最常见的转换成 字符串.3."订单"+2514 //后面的数字会转换为字符串.4.((类名A)对象名X) //强行将 对象X 转换成 A类 的对象.5.int.Parse(string);把字符串型转换成其他类型.6.还有,如果要转换成的类型为引用类型,还可以用 as teacher tea = teahcer();如 student stu = tea as student; (1)

  • 全面了解JavaScript的数据类型转换

    首先,由于JavaScript是弱类型语言(弱类型的语言的东西没有明显的类型,他能随着环境的不同,自动变换类型而强类型则没这样的规定,不同类型间的操作有严格定义,只有相同类型的变量才能操作,虽然系统也有一定的默认转换,当绝没有弱类型那么随便,也就是说变量在声明时不需要指定数据类型,变量由赋值操作确定数据类型),所以在JavaScript的类型转换中就存在了强类型语言所没有的隐式转换. 1.1 JavaScript中的隐式转换(自动类型转换) 简单定义: 不同数据类型的数据在做运算的时候可以进行默

随机推荐