数据类型转换

数据类型转换

一、隐式类型转换

1)简单数据类型

(1)算术运算

转换为最宽的数据类型

eg:

#include <iostream>

using std::cout;
using std::endl;

int main(int argc, char* argv[])
{
	int ival = 3;
	double dval = 3.14159;

	cout << ival + dval << endl;//ival被提升为double类型
	return 0;
}
其运行结果:
6.14159
int main(int argc, char* argv[])
{
010D17D0  push        ebp  
010D17D1  mov         ebp,esp  
010D17D3  sub         esp,0DCh  
010D17D9  push        ebx  
010D17DA  push        esi  
010D17DB  push        edi  
010D17DC  lea         edi,[ebp-0DCh]  
010D17E2  mov         ecx,37h  
010D17E7  mov         eax,0CCCCCCCCh  
010D17EC  rep stos    dword ptr es:[edi]  
int ival = 3;
010D17EE  mov         dword ptr [ival],3  
double dval = 3.14159;
010D17F5  movsd       xmm0,mmword ptr [__real@400921f9f01b866e (010D6B30h)]  
010D17FD  movsd       mmword ptr [dval],xmm0  


cout << ival + dval << endl;//ival被提升为double类型
010D1802  mov         esi,esp  
010D1804  push        offset std::endl<char,std::char_traits<char> > (010D1064h)  
010D1809  cvtsi2sd    xmm0,dword ptr [ival]  
010D180E  addsd       xmm0,mmword ptr [dval]  
010D1813  mov         edi,esp  
010D1815  sub         esp,8  
010D1818  movsd       mmword ptr [esp],xmm0  
010D181D  mov         ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (010D90A8h)]  
010D1823  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (010D90A0h)]  
010D1829  cmp         edi,esp  
010D182B  call        __RTC_CheckEsp (010D111Dh)  
010D1830  mov         ecx,eax  
010D1832  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (010D90A4h)]  
010D1838  cmp         esi,esp  
010D183A  call        __RTC_CheckEsp (010D111Dh)  
return 0;
010D183F  xor         eax,eax  
}
010D1841  pop         edi  
}
010D1842  pop         esi  
010D1843  pop         ebx  
010D1844  add         esp,0DCh  
010D184A  cmp         ebp,esp  
010D184C  call        __RTC_CheckEsp (010D111Dh)  
010D1851  mov         esp,ebp  
010D1853  pop         ebp  
010D1854  ret  

(2)赋值

转换为被赋值对象的类型,但不会改变赋值对象的数据类型。

eg:

#include <iostream>

using std::cout;
using std::endl;

int main(int argc, char* argv[])
{
	int ival = 4;
	double dval = 3.14159;
	ival = dval; // double->int
	cout << dval << endl;
	cout << ival << endl;
	return 0;
}
其运行结果:
3.14159
3
注意:数据类型窄化转换时,注意数据溢出及丢失。

(3)函数传参 
当实参与形参数据类型不同时,转换为形参数据类型。
eg:
#include <iostream>

using std::cout;
using std::endl;

double square(double dval);

int main(int argc, char* argv[])
{
	cout << square(5) << endl;
	return 0;
}

double square(double dval)
{
	return dval * dval;
}
其运行结果:
25

(4)函数返回

当返回类型与表达式类型不同时,转换为返回类型。

eg:

#include <iostream>

using std::cout;
using std::endl;

double difference(int ival1, int ival2);

int main(int argc, char* argv[])
{
	int ival1 = 2;
	int ival2 = 3;
	cout << difference(2, 3) << endl;
	return 0;
}

double difference(int ival1, int ival2)
{
	return ival1 - ival2; 	//返回值被提升为double类型
}

其运行结果:

-1


2)类类型
(1)单参数构造函数

(2)赋值操作符

(3)类型转换操作符

eg:
// implicit conversion of classes:
#include <iostream>

using std::cout;
using std::endl;

class A {};

class B {
public:
	// conversion from A (constructor)
	B(const A& x)
	{
		cout << "Conversion from A (constructor)" << endl;
	}

	// conversion from A (assignment)
	B& operator= (const A& x)
	{
		cout << "Conversion from A (assignment)" << endl;
		return *this;
	}

	// conversion to A (type-cast operator)
	operator A()
	{
		cout << "Conversion to A (type-cast operator)" << endl;
		return A();
	}
};

int main(int argc, char* argv[])
{
	A foo;
	B bar = foo;    // calls constructor
	bar = foo;      // calls assignment
	foo = bar;      // calls type-cast operator
	return 0;
}

其运行结果:

Conversion from A (constructor)

Conversion from A (assignment)

Conversion to A (type-cast operator)


二、显示类型转换

1)C风格
dst = (T)src

eg:

#include <iostream>

using std::cout;
using std::endl;

int main(int argc, char* argv[])
{
	int ival;
	double dval = 3.14159;
	ival = (int)dval; // double->int
	cout << dval << endl;
	cout << ival << endl;
	return 0;
}
其运行结果:
3.14159
3

2)函数风格

dst = T(src)

eg:

#include <iostream>

using std::cout;
using std::endl;

int main(int argc, char* argv[])
{
	int ival;
	double dval = 3.14159;
	ival = int(dval); // double->int
	cout << dval << endl;
	cout << ival << endl;
	return 0;
}

其运行结果:

3.14159

3


3)

(1)static_cast
a、 类层次结构中基类和派生类之间指针或者引用的转换。up-casting (把派生类的指针或引用转换成基类的指针或者引用表示)是安全的;down-casting(把基类指针或引用转换成子类的指针或者引用)是不安全的。
b、基本数据类型之间的转换
c、把空指针转换成目标类型的空指针(null pointer)
d、 把任何类型的表达式转换成void类型
注意:不能转换掉表达式的const、volitale或者__unaligned属性。
eg1:
#include <iostream>

using std::cout;
using std::endl;

class Dummy 
{
	double i, j;
};

class Addition 
{
	int x, y;
public:
	Addition(int a, int b) { x = a; y = b; }
	int result() { return x + y; }
};

int main(int argc, char* argv[])
{
	Dummy d;
	Addition * padd;
	padd = (Addition*)&d;
	cout << padd->result();
	return 0;
}
其运行结果:
-1717986920
不做类型检查,转换没有安全性

eg2:

#include <iostream>

using std::cout;
using std::endl;

class Dummy 
{
	double i, j;
};

class Addition 
{
	int x, y;
public:
	Addition(int a, int b) { x = a; y = b; }
	int result() { return x + y; }
};

int main(int argc, char* argv[])
{
	Dummy d;
	Addition * padd;
	padd = static_cast<Addition*>(&d);
	cout << padd->result();
	return 0;
}

(2)dynamic_cast
转换类型与表达式类型相同,必须同时是类的指针、类的引用或void *.用于类的上行、下行及交叉转换。一般情况下,dynamic_cast用于具有多态性的类(即有虚函数的类)的类型转换。
a、上行转换时,其与static_cast效果相同;
b、下行转换时,其具有类型转换的功能,比static_cast更安全;
c、交叉转换时,其转换成空指针,而static_cast则不允许转换。
注意:不能转换掉表达式的const、volitale或者__unaligned属性。

eg:

// dynamic_cast
#include <iostream>
#include <exception>

using std::cout;
using std::endl;
using std::exception;

class Base { virtual void dummy() {} };
class Derived : public Base { int a; };

int main(int argc, char* argv[]) 
{
	try {
		Base * pba = new Derived;
		Base * pbb = new Base;
		Derived * pd;

		pd = dynamic_cast<Derived*>(pba);
		if (pd == 0) cout << "Null pointer on first type-cast.\n";

		pd = dynamic_cast<Derived*>(pbb);
		if (pd == 0) cout << "Null pointer on second type-cast.\n";

	}
	catch (exception& e) { cout << "Exception: " << e.what(); }
	return 0;
}
其运行结果:
Null pointer on second type-cast.

(3)reinterpret_cast

转换一个指针为其他类型的指针,也允许将一个指针转换为整数类型,反之亦然。这个操作符能够在非相关的类型之间进行转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝,在类型之间指向的内容不做任何类型的检查和转换。这是一个强制转换。使用时有很大的风险,慎用之。

注意:不能转换掉表达式的const、volitale或者__unaligned属性。

eg1:

// expre_reinterpret_cast_Operator.cpp
// compile with: /EHsc
#include <iostream>

using std::cout;
using std::endl;

// Returns a hash code based on an address
unsigned short Hash(void *p)
{
	unsigned int val = reinterpret_cast<unsigned int>(p);
	return (unsigned short)(val ^ (val >> 16));
}

int main(int argc, char* argv[])
{
	int a[20];
	for (int i = 0; i < 20; i++)
		cout << Hash(a + i) << endl;
}
其运行结果:


eg2:
#include <iostream>

struct Foo {};
struct Bar {};

int main()
{
	Foo* f = new Foo;

	Bar* b1 = f;
	Bar* b2 = static_cast<Bar*>(f);
	Bar* b3 = dynamic_cast<Bar*>(f);
	Bar* b4 = const_cast<Bar*>(f);
	Bar* b5 = reinterpret_cast<Bar*>(f);

	return 0;
}
1>------ 已启动全部重新生成: 项目: test, 配置: Debug Win32 ------
1>  main.cpp
1>f:\workspace\test\test\main.cpp(10): error C2440: “初始化”: 无法从“Foo *”转换为“Bar *”
1>  f:\workspace\test\test\main.cpp(10): note: 与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换
1>f:\workspace\test\test\main.cpp(11): error C2440: “static_cast”: 无法从“Foo *”转换为“Bar *”
1>  f:\workspace\test\test\main.cpp(11): note: 与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换
1>f:\workspace\test\test\main.cpp(12): error C2683: “dynamic_cast”:“Foo”不是多态类型
1>  f:\workspace\test\test\main.cpp(3): note: 参见“Foo”的声明
1>f:\workspace\test\test\main.cpp(13): error C2440: “const_cast”: 无法从“Foo *”转换为“Bar *”
1>  f:\workspace\test\test\main.cpp(13): note: 与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换
========== 全部重新生成: 成功 0 个,失败 1 个,跳过 0 个 ==========

(4)const_cast

修改类型的const或volatile属性

a、常量指针被转化成非常量指针,转换后指针指向原来的变量(即转换后的指针地址不变)

eg1:

// const_cast
#include <iostream>

using std::cout;
using std::endl;

void print(char * str)
{
	cout << str << endl;
}

int main(int argc, char* argv[]) 
{
	const char * c = "sample text";
	print(const_cast<char *> (c));
	return 0;
}

其运行结果:
sample text

eg2:
#include <iostream>

using std::cout;
using std::endl;

class A
{
public:
	A()
	{
		m_iNum = 0;
	}
	int m_iNum;
};

int main(int argc, char* argv[])
{
	//1、指针指向类  
	const A *pca1 = new A;
	A *pa2 = const_cast<A*>(pca1);  //常量对象转换为非常量对象  
	pa2->m_iNum = 200;    
	//转换后指针指向原来的对象  
	cout << pca1->m_iNum  << " " << pa2->m_iNum << endl; //200 200  

	//2、指针指向基本类型  
	const int ica = 100;
	int * ia = const_cast<int *>(&ica);
	*ia = 200;
	cout << *ia  << " " << ica << endl;   //200 100  
	return 0;
}
其运行结果:
200 200
200 100

b、常量引用转为非常量引用

eg:

#include <iostream>

using std::cout;
using std::endl;

class A
{
public:
	A()
	{
		m_iNum = 1;
	}
	int m_iNum;
};

int main(int argc, char* argv[])
{
	A a0;
	const A &a1 = a0;
	A a2 = const_cast<A&>(a1); //常量引用转为非常量引用  
	a2.m_iNum = 200;    
	cout << a0.m_iNum << endl;
	cout << a1.m_iNum << endl;
	cout << a2.m_iNum << endl; 
	return 0;
}
其运行结果:
1
1
200

c、常量对象(或基本类型)不可以被转换成非常量对象(或基本类型)
eg:
#include <iostream>

using std::cout;
using std::endl;

class A
{
public:
	A()
	{
		m_iNum = 1;
	}
	int m_iNum;
};

int main(int argc, char* argv[])
{
	//常量对象被转换成非常量对象时出错  
	const A ca;
	A a = const_cast<A>(ca);  //不允许  

	const int i = 100;
	int j = const_cast<int>(i);  //不允许  
	return 0;
}

d、添加const属性
eg:
#include <iostream>

using std::cout;
using std::endl;

int main(int argc, char* argv[])
{
	int i = 100;
	int *j = &i;
	const int *k = const_cast<const int*>(j);
	//const int *m = j;   感觉和这样写差不多

	//指的地址都一样
	cout << i << "," << &i << endl;
	cout << *j << "," << j << endl; 
	cout << *k << "," << k << endl; 

	*j = 200;
	cout << i << "," << &i << endl;
	cout << *j << "," << j << endl;
	cout << *k << "," << k << endl;

	return 0;
}

其运行结果:


参考文献

[1]static_cast,dynamic_cast,reinterpret_cast和const_cast的区别详解. http://www.jb51.net/article/41377.htm.

[2] static_cast,dynamic_cast, const_cast探讨. http://www.cnblogs.com/chio/archive/2007/07/18/822389.html.

[3]static_cast. http://baike.baidu.com/link?url=k_oO_od3IQcIQFhxs39iqAu5hU5AoT5rtAv5d2a6yXSSXCb8y0EIvnlT_vqR0fqpXReqsfqXan4-UPCTL6ZILK.

[4] reinterpret_cast.http://baike.baidu.com/link?url=Db0gF69eNavQmAJ_SjkD88t9s9bmEd1eHh8-pYezezH-Xl8wAGC3pK_Lx6pRlL4262m9tgT2FOQjiO6KjonqFq.

[5] 之四、static_cast. http://blog.csdn.net/jofranks/article/details/7828331.

[6] 之三、const_cast. http://blog.csdn.net/jofranks/article/details/7828326.

[7] 之二、static_cast和dynamic_cast、reinterpret_cast. http://blog.csdn.net/jofranks/article/details/7816046.

[8] 之五、dynamic_cast. http://blog.csdn.net/jofranks/article/details/7828335.

[9] 之六、reinterpret_cast. http://blog.csdn.net/jofranks/article/details/7828339.

[10]static_cast, dynamic_cast, reinterpret_cast, const_cast区别比较. http://www.cnblogs.com/jerry19880126/archive/2012/08/14/2638192.html.

[11]dynamic_cast Operator. https://msdn.microsoft.com/en-us/library/cby9kycs?f=255&MSPPError=-2147217396.

[12]static_cast Operator. https://msdn.microsoft.com/en-us/library/c36yw7x9.aspx?f=255&MSPPError=-2147217396.

[13] const_castOperator. https://msdn.microsoft.com/en-us/library/bz6at95h.aspx.

[14] reinterpret_castOperator. https://msdn.microsoft.com/en-us/library/e0w9f63b.aspx.

[15] Regularcast vs. static_cast vs. dynamic_cast [duplicate].  http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast.

[16] Typeconversions. http://www.cplusplus.com/doc/tutorial/typecasting/.

[17] C++dynamic_cast实现原理. http://blog.csdn.net/passion_wu128/article/details/38511957.

[18] TYPE CASTOPERATORS – 2016. http://www.bogotobogo.com/cplusplus/typecast.php.

[19] C++类型转换详解--const_cast. http://blog.csdn.net/lwbeyond/article/details/6213382.

 

注:为了便于自己学习,无心侵权,尽可能将所引用的文章列举出来;有些文章的内容可能会与原作重复度较高,还请谅解。如作者举报,愿意删除此文。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值