对C++中类型转换的一些探讨
来源:互联网 发布:淘宝哪家店买手办 编辑:程序博客网 时间:2024/06/05 08:03
类型转换经常发生在变量赋值(或初始化)、函数参数传递、函数返回值等地方。首先要注意一点:不管是显示的类型转换还是隐式的类型转换,都有一个到转换结果类型的临时变量的产生:
譬如:
int i = 1.2; //实际的赋值过程可能是 int temp = 1.2; int i = temp;
所以这就很能解释下面这个错误:
double d = 2.1;
int &ri = d; //错误!因为这里ri的引用是对保存类型转换结果的那个临时变量的引用。
int *pi = &d; //错误,这里很明显视图将一块表示浮点数的内存区域用int来解释。
同样也能够解释函数参数传递中不允许传递到引用的类型转换和使用引用返回局部对象。因为保存函数返回值的匿名变量也是在函数调用栈区的,返回语句所做的就是去初始化该匿名变量,如果这个初始化的过程还有类型转换的话,那么同样有类型转换的临时变量的产生。(可以参看B.S《C++ 程序设计语言》P130~P133)
再来分析一下显示强制类型转换:
int _tmain(int argc, _TCHAR* argv[])
{
float i = 5;
//1 static_cast<int>(i) = 4; //错误!
//2 static_cast<int&>(i) = 4 //错误!
//3 static_cast<float>(i) =4; //正确
//4 static_cast<float&>(i) = 4; //正确
cout<<i<<endl;;
return 0;
}
注意强制类型转换运算符的返回值为存储转换结果的临时变量,4是正确的,应为该临时变量是对i的引用,所以输出4;3是正确的,同样结果输出4,可以认为是转换前后类型相同,所以实际上转换根本不发生,所以3实际上等于:i =4;2很明显是错误的把float转换到int&;1是错误的编译出错信息是“'=' : left operand must be l-value”,实际上可以理解为该转换结果的临时变量赋值是不安全且完全没有必要的。
最后在分析下显示强制类型转换和多态的组合:
在派生类的赋值运算符的实现中,会经常发现static_cast<base&>(*this) = rhs;此类的语句来调用该派生类基类成员的operator=,这里的从派生类对象derived到临时变量基类对象的引用base&是可行的(多态),然后再调用基类的operator=操作符。
再来讨论类型转换后存放变量的内存空间的变化:
大部分的类型转换后存放变量的内存空间肯定有了变化。但要注意无符号变量和有符号变量之间的转换是其对应的内存地址二进制表示不变。
unsigned char 到char的转换内存二进制表示不变。所以可以互相转换。
#include "stdafx.h"
#include <iostream>
#include <fstream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
unsigned char uc = 129;
ofstream ofs("out.txt", ios::binary);
cout<<(int)uc<<endl;
ofs.write((char*)&uc, sizeof(uc));
char c = char(uc);
cout<<(int)c<<endl;
ofs.write(&c, sizeof(c));
ofs.close();
return 0;
}
打开out.txt,切换到二进制查看模式,都是0x81.
由于转换到int过程中对内存地址的解释的不同,
控制台输出: 129(unsigned char 内存0x81第一个bit解释为数字位)
-127(char 内存0x81第一个bit解释为符号位,0x81为-127的补码表示)
下面这段代码可能更加清楚一些,可以看出对同一块内存地址0x81,不同的类型解释,得到不同的结果。
int _tmain(int argc, _TCHAR* argv[])
{
unsigned char uc = 129;
unsigned char *puc = &uc;
char *pc = (char*)puc;
cout<<int(*puc)<<endl;
cout<<int(*pc)<<endl;
return 0;
}
输出: 129
-127
譬如:
int i = 1.2; //实际的赋值过程可能是 int temp = 1.2; int i = temp;
所以这就很能解释下面这个错误:
double d = 2.1;
int &ri = d; //错误!因为这里ri的引用是对保存类型转换结果的那个临时变量的引用。
int *pi = &d; //错误,这里很明显视图将一块表示浮点数的内存区域用int来解释。
同样也能够解释函数参数传递中不允许传递到引用的类型转换和使用引用返回局部对象。因为保存函数返回值的匿名变量也是在函数调用栈区的,返回语句所做的就是去初始化该匿名变量,如果这个初始化的过程还有类型转换的话,那么同样有类型转换的临时变量的产生。(可以参看B.S《C++ 程序设计语言》P130~P133)
再来分析一下显示强制类型转换:
int _tmain(int argc, _TCHAR* argv[])
{
float i = 5;
//1 static_cast<int>(i) = 4; //错误!
//2 static_cast<int&>(i) = 4 //错误!
//3 static_cast<float>(i) =4; //正确
//4 static_cast<float&>(i) = 4; //正确
cout<<i<<endl;;
return 0;
}
注意强制类型转换运算符的返回值为存储转换结果的临时变量,4是正确的,应为该临时变量是对i的引用,所以输出4;3是正确的,同样结果输出4,可以认为是转换前后类型相同,所以实际上转换根本不发生,所以3实际上等于:i =4;2很明显是错误的把float转换到int&;1是错误的编译出错信息是“'=' : left operand must be l-value”,实际上可以理解为该转换结果的临时变量赋值是不安全且完全没有必要的。
最后在分析下显示强制类型转换和多态的组合:
在派生类的赋值运算符的实现中,会经常发现static_cast<base&>(*this) = rhs;此类的语句来调用该派生类基类成员的operator=,这里的从派生类对象derived到临时变量基类对象的引用base&是可行的(多态),然后再调用基类的operator=操作符。
再来讨论类型转换后存放变量的内存空间的变化:
大部分的类型转换后存放变量的内存空间肯定有了变化。但要注意无符号变量和有符号变量之间的转换是其对应的内存地址二进制表示不变。
unsigned char 到char的转换内存二进制表示不变。所以可以互相转换。
#include "stdafx.h"
#include <iostream>
#include <fstream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
unsigned char uc = 129;
ofstream ofs("out.txt", ios::binary);
cout<<(int)uc<<endl;
ofs.write((char*)&uc, sizeof(uc));
char c = char(uc);
cout<<(int)c<<endl;
ofs.write(&c, sizeof(c));
ofs.close();
return 0;
}
打开out.txt,切换到二进制查看模式,都是0x81.
由于转换到int过程中对内存地址的解释的不同,
控制台输出: 129(unsigned char 内存0x81第一个bit解释为数字位)
-127(char 内存0x81第一个bit解释为符号位,0x81为-127的补码表示)
下面这段代码可能更加清楚一些,可以看出对同一块内存地址0x81,不同的类型解释,得到不同的结果。
int _tmain(int argc, _TCHAR* argv[])
{
unsigned char uc = 129;
unsigned char *puc = &uc;
char *pc = (char*)puc;
cout<<int(*puc)<<endl;
cout<<int(*pc)<<endl;
return 0;
}
输出: 129
-127
- 对C++中类型转换的一些探讨
- 对java中double类型的精度问题探讨
- NS2中对一些类型的定义
- MFC中一些类型的转换
- c语言的一些总结和探讨(未完待续中).
- c语言的一些总结和探讨(未完待续中).
- C语言中 对变量内存关系的探讨
- 关于php基础类型的一些探讨
- Java基本类型的一些问题探讨
- 整理一些C#中常用的一些类型转换_ts
- 【C#】中Decimal类型转换的问题
- C中常见的类型转换
- 对C#中HashTable的Add方法参数类型的探讨
- 对C++中类类型的转换的认识
- Spring MVC中对Date类型操作的一些问题解决
- java中对Date类型的一些处理
- Windows编程中一些常用的字符(串)类型转换
- Javascript中关于类型转换的一些问题
- C++ 学习练手 - 双向链表的模板实现
- Delphi中的继承机制
- Windows Mobile 5.0 SDK 下载地址(转)
- Internet Explorer 编程简述(六)自定义浏览器上下文菜单
- VC++中CTime类format的使用
- 对C++中类型转换的一些探讨
- virtual function 与 访问权限没有关系
- C#一次性清空TextBox或者将某一类控件置某一状态
- 在SQL SERVER里显示到期的内容
- VS2005+Crystal Report开发Web应用
- 批处理脚本学习Summary
- Internet Explorer 编程简述(七)完美的“编码”菜单
- 清除VS2005最近项目列表
- 学习ARM开发(1)