C++Primer学习——类型转换
无符号之间的运算
当一个是无符号类型,另外一个是带符号类型:
如果无符号不小于带符号,那么带符号转换成无符号。
如果无符号小于带符号,当无符号类型的所有值都能存到带符号中时,则无符号转换成带符号,否则,
带符号类型转换成无符号类型。
比如:
有两个类型分别是 long 和 unsigned int,如果大小相同,long类型转换成unsigned int,否则unsigned转换成long类型
隐式类型:
数组转换成指针:
decltype,取地址&,sizeof以及typeid(未知)不会转换
如果用一个引用初始化数组也不会发生转换。(引用初始化数组?)
类类型定义的转换:
string s;
while(cin >> s) //IO库定义了从istream向bool的转换规则,取决于是否读入成功
{
}
显式转换:
cast-name(exp); 将exp转换成type类型
1、static_cast:(只要不包含底层const)
主要在以下几种场合中使用:
1.用于类层次结构中,基类和子类之间指针和引用的转换;
当进行上行转换,也就是把子类的指针或引用转换成父类表示,这种转换是安全的;
当进行下行转换,也就是把父类的指针或引用转换成子类表示,这种转换是不安全的,也需要程序员来保证;
2.用于基本数据类型之间的转换,如把int转换成char,把int转换成enum等等,这种转换的安全性需要程序员来保证;
3.把void指针转换成目标类型的指针,是及其不安全的;
注:static_cast不能转换掉expression的const、volatile和__unaligned属性。
参考链接
int a = 100;
double t = static_cast<double>(a) / 6;
cout << t << endl;
//16.6667
向上转换(好像并不是肯定安全的记住原始的指针类型 ?):
class Base1{
//int a;
};
class Base2{
public:
int b;
};
class Derived: public Base1, public Base2{
};
int main()
{
int a;
void *p;
Derived pd;
pd.b = 10;
cout << pd.b <<endl;
cout << "pb: " << &pd<< endl;
Base2* pb1 = static_cast<Base2 *>(&pd);
cout << pb1->b <<endl;
cout << "Derived to Base2: " << pb1 << endl;
return 0;
}
10
pb: 0x68fefc
10
Derived to Base2: 0x68fefc
2、const_cast:(只能改变底层const)
使用const_cast去除const限定的目的不是为了修改它的内容,通常是为了函数能够接受这个实际参数
const char *cp;
char *p = const_cast<char*>(cp);//通过p写值是未定义行为
char *p = static_cast<char*>(cp);//error
static_cast<string>(cp); //yes,字符串字面值转变成string(未实践)
const int a = 100;
int *pA = const_cast<int *>(&a);
*pA = 200;
int &refA = const_cast<int &>(a);
refA = 300;
// int *pA1 = static_cast<int *>(&a); Error
cout << "*pA:" << *pA << endl;//300
cout << "refA:" << refA << endl;//300
cout << "a:" << a << endl;//100
system("pause");
下面是网上摘录的一段解释:(or常量折叠解释)
const只是告诉编译器不能修改而不是真正地不可修改,如果程序员不注意而去修改了它会报错,现在我们利用const_cast去除了常量性,然后通过指针和引用对其进行了修改,所以通过指针打印或者引用传参的时候就能看出其内存确实变化了,但为了保护val这个变量本来的const特性,所以每次我们使用val时,系统都将其替换成初始值100,确保了val还是“不可变”的
参考博客
#include <iostream>
using namespace std;
void f(int* p) {
cout << *p << endl;
}
int main(void) {
const int a = 10;
const int* b = &a;
// Function f() expects int*, not const int*
// f(b);
int* c = const_cast<int*>(b);
f(c);
// Lvalue is const
// *b = 20;
// Undefined behavior
// *c = 30;
int a1 = 40;
const int* b1 = &a1;
int* c1 = const_cast<int*>(b1);
// Integer a1, the object referred to by c1, has
// not been declared const
*c1 = 50;
return 0;
}
http://www.ibm.com/support/knowledgecenter/SS3KZ4_9.0.0/com.ibm.xlcpp9.bg.doc/language_ref/keyword_const_cast.htm
在函数重载上面的应用:
const string &shorterString(const string& a, const string& b)
{
return a.size() <= b.size() ? a : b;
}
string &shorterString(string& a, string& b)
{
auto &r = shorterString(const_cast<const string&>(a),
const_cast<const string&>(b));
return const_cast<string &>(r);
}
3、reinterpret_cast:(本质上依赖于机器)
可以进行任意之间的转换,不会报错,但是可能破坏程序
int *ip;
char *pc = reinterpret<char*>(ip);
string str(pc); //pc所指真实对象是一个int,所以有问题
与旧式转换类似的功能
int *op;
char *p = (char*)op;
MSDN上的一个应用- - ,不是很懂reinteroret_cast有什么用
#include <iostream>
using namespace std;
// 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));
}
using namespace std;
int main() {
int a[20];
for ( int i = 0; i < 20; i++ )
cout << Hash( a + i ) << endl;
}
4.dynamic_cast转换 :
(想使用基类指针或者引用执行某个派生类非虚函数操作)
dynamic_cast是动态转换,只有在基类指针转换为子类指针时才有意义。(子类指针转换为基类指针本来就是可以的:基类指针指向子类对象OK)。
但是基类指针转换为子类指针,并不是每一次都有效:只有基类指针本身指向的是一个派生类的对象,
安全性:
这需要从它的返回值进行讨论,如果符合继承体系且原始指针是指向派生类的对象的,那么返回值将是一个正确的指针值,否则会返回NULL。所以,我们可以对返回值进行判断来进行断定到底转换是否正确,从而保证程序的健壮性
必须是一个带有虚函数的类。因为dynamic_cast是在对象的内存模型中保存了offset值来实现转换的,这些offset值是保存在虚表(vtbl)中的
虚表参考<Inside c++ object model>:
class MyCompany
{
public:
void payroll(Employee *pe);
//
};
void MyCompany::payroll(Employee *pe)
{
Programmer *pm = dynamic_cast<Programmer *>(pe);
//如果pe实际指向一个Programmer对象,dynamic_cast成功,并且开始指向Programmer对象起始处
if(pm)
{
//call Programmer::bonus()
}
//如果pe不是实际指向Programmer对象,dynamic_cast失败,并且pm = 0
else
{
//use Employee member functions
}
}
class A
{
public:
virtual ~A(){} //虚函数 多态
};
class B:public A
{
public:
int m;
};
A* pObjA = new A();
B* pObjB = NULL;
pObjB = dynamic_cast<B*>(pObjA); //编译通过
//实际运行结果:pObjB == NULL // dynamic_cast保证转换无效 返回NULL
来自为知笔记(Wiz)
C++Primer学习——类型转换的更多相关文章
- C++ Primer学习笔记(二)
题外话:一工作起来就没有大段的时间学习了,如何充分利用碎片时间是个好问题. 接 C++ Primer学习笔记(一) 27.与 vector 类型相比,数组的显著缺陷在于:数组的长度是固定的,无法 ...
- C++ Primer学习笔记(三) C++中函数是一种类型!!!
C++中函数是一种类型!C++中函数是一种类型!C++中函数是一种类型! 函数名就是变量!函数名就是变量!函数名就是变量! (---20160618最新消息,函数名不是变量名...囧) (---201 ...
- 转载:看c++ primer 学习心得
学习C++ Primer时遇到的问题及解释 chenm91 感觉: l 啰嗦有时会掩盖主题:这本书确实有些啰嗦,比如在讲函数重载的时候,讲了太长一大段(有两节是打了*号的,看还是不看 ...
- c++ primer 学习杂记2【派生类到基类转换的可访问性】
参考: http://blog.csdn.net/rehongchen/article/details/7930853 http://blog.csdn.net/ming_road/article/d ...
- C++ Primer 学习笔记_76_模板与泛型编程 --模板定义[续]
模板与泛型编程 --模板定义[续] 四.模板类型形參 类型形參由keywordclass或 typename后接说明符构成.在模板形參表中,这两个keyword具有同样的含义,都指出后面所接的名字表示 ...
- C++ primer学习记录(个人猜想未测试版本)
学习版本:第五版. 本博文主要记录个人曾经并不知晓知识细节. 因为linux下的编译环境还未进行学习.所以实际代码测试将在今后完成. 红色:需确认. 蓝色:重点. 1)const对象设定为仅在文件内有 ...
- C++ Primer学习笔记2--c++标准库中的 vector、string 和 bitset 类型
一.string #include <string> using std::string 初始化函数: string s1; 默认构造函数 s1 为空串 ...
- C++ Primer 学习笔记_76_模板和泛型编程 --模板定义[继续]
模板和泛型编程 --模板定义[续] 四.模板类型形參 类型形參由keywordclass或 typename后接说明符构成.在模板形參表中,这两个keyword具有同样的含义,都指出后面所接的名字表示 ...
- C++ Primer 学习笔记_32_STL实践与分析(6) --再谈string类型(下)
STL实践与分析 --再谈string类型(下) 四.string类型的查找操作 string类型提供了6种查找函数,每种函数以不同形式的find命名.这些操作所有返回string::size_typ ...
随机推荐
- 20155306 2017-2018-1《信息安全系统设计》第二周课堂测试以及myod的实现
20155306 2017-2018-1<信息安全系统设计>第二周课堂测试以及myod的实现 第二周课堂测验: (注:前两项在课堂已提交,在此不做详解) 第一项: 每个.c一个文件,每个. ...
- 团队作业4——第一次项目冲刺(Alpha版本) Day 1
小队@JMUZJB-集美震惊部 一.Daily Scrum Meeting照片 二.Burndown Chart 燃尽图 三.项目进展 1.界面 屏幕开发中,原型设计完毕. 2.服务器 服务器由学校提 ...
- Python 科学计算-介绍
Python 科学计算 作者 J.R. Johansson (robert@riken.jp) http://dml.riken.jp/~rob/ 最新版本的 IPython notebook 课程文 ...
- Scala 操作符与提取器
实际上Scala没有操作符, 只是以操作符的格式使用方法. 操作符的优先级取决于第一个字符(除了赋值操作符), 而结合性取决于最后一个字符 Scala的操作符命名更加灵活:) 操作符 中置操作符(In ...
- 关于网页设计的css+html相对定位和决定定位的理解
css中有很多定位,其中最重要的是相对定位和绝对定位: 定位很重要,不搞好,网页就会很乱,显示的完全不是自己想要的效果,自己必须掌握: 首先说一个重要的结论:绝对定位,是不占位置的,总是相对离自己最近 ...
- vmware 12 安装 mac os 10.12正式版
1.首先下载安装vmware 12 pro ,将VT打开(虚拟功能,以前安装过虚拟机点的同学可忽略). 2.下载mac ox 10.12正式版镜像文件(cdr后缀). 3.下载Unlocker208( ...
- JQ 标签相关知识
1.判断 checkbox 和 radio 是否选中 if($("标签选择器").is(":checked")) 2.改变 checkbox 选中状态 .pro ...
- 分贝块---dBblock
分贝,用英语来表达的话,是decibel,是量度两个相同单位之数量比例的计量单位,主要用于度量声音强度,常用dB表示. 块,block,在百度百科中,指数据库中的最小存储和处理单位,包含块本身的头信息 ...
- python利用递归函数输出嵌套列表的每个元素
1.先用 for 循环取. for item in l: if isinstance(item ,list): for newitem in item: print(newitem) else: pr ...
- System Rules 更好的测试
1:编写测试事例时候,我们要从控制台拿到数据与断言进行对比,通常要编写jdk 标准输出的屏蔽控制器.文章标题的包,能够更好的为我们进行工作. package demo2; import static ...