c++primer 第4章 表达式

4.1 基础

  • 表达式:对表达式求值将得到一个结果,字面值和变量是最简单的表达式,其结果就是字面值和变量的值

4.1.1 基本概念

组合运算符和运算对象

运算对象转换

小整数类型(bool,char,short)通常会被提升成较大的整数类型主要是int

重载运算符

  • 我们使用承载运算符时,其包括运算对象的类型和返回值的类型.都是由该运算符定义的.但是运算对象的个数.运算符的优先级和结合律都是无法改变的.

左值和右值

  • C++表达式要不是左值要不是右值
  • 当一个对象被用作右值的时候,用的是对象的值.当对象被用作左值的时候,用的是对象的身份.(在内存中的位置)
  • 在需要右值的地方可以用左值来代替,但是不能把右值当做左值来使用.
    几种熟悉的运算符要用到左值
  1. 赋值运算符需要一个左值作为其左侧运算对象,得到结果页仍然是一个左值
  2. 取地址符作用于一个左值运算对象,返回一个指向该运算对象的指针,这个指针是一个右值
  3. 内置解引用运算符,下标运算符,迭代器解引用运算符,string和vector的下标运算符的求值结果都是左值
  • decltype作用于表达式求值结果是左值的将得到得到一个引用类型.
int * p;
decltype(*p);的结果是int&;
  • decltype作用表达式求值结果是右值
decltype(&p) 得到int**

4.1.2 优先级和结合律

4.1.3 求值顺序

4.2算数运算符

bool b = true;
book b2 = -b; // b2是true
  • 如上所示,参与运算时布尔将被提升成整数值1,然后对他求负值的结果是-1,将-1转换为bool值为true

4.3逻辑和关系运算符

4.4赋值运算符

int ival,jval;
ival=jval=0;
  • 因为运算符对象满足右结合律,所以靠右的赋值运算jval=0作为靠左的赋值运算符的右侧运算对象.又因为赋值运算符返回的是左侧运算对象,所以靠右的赋值运算的结果(即jval)被赋值给ival

4.5递增和递减运算符

在这里插入图片描述

4.6成员访问运算符

4.7条件运算符

4.8位运算符

4.9sizeof运算符

  1. 对char或者类型为char的表达式执行sizeof运算结果得1
  2. 对引用类型执行sizeof得到被引用对象所占空间的大小
  3. 对解引用指针指向sizeof得到指针所指向的对象所占空间的大小,指针不需要有效
  4. 对数组执行sizeof得到整个数组所占空间的大小
  5. 对string对象或者vector对象执行sizeof只返回该类型固定部分的大小,不会计算对象中的元素占用了多少空间
int x[10];
int *p=x;
cout<<sizeof(x)/sizeof(*x);//10
cout<<sizeof(p)/sizeof(*x);//1
//sizeof(p)的运算对象是一个指针,求值结果是指针所占的空间的大小,sizeof(x)的运算对象x是数组的名字,求值结果是整个数组所占空间的大小

4.10逗号运算符

4.11类型运算符

  • 如果两种类型可以相互转换,那么他们就是相互关联的

何时发生隐式类型转换

在这里插入图片描述

4.11.1算数转换

  • 运算符的运算对象将转换成最宽的类型

整型提升

无符号类型的运算对象

  • 如果一个运算对象是无符号类型,另外一个运算对象是带符号类型,而且其中的无符号类型不小于带符号类型,那么带符号的运算对象转换成无符号类型.例如:unsigned和int,则int类型转换为unsigned类型
    在这里插入图片描述
    在这里插入图片描述

4.11.2 其他隐式类型转换

数组转换成指针

  • 在大多数用到数组的表达式中,数组自动转换成指向数组首元素的指针
int a[10];
int * ip = ia;
  • 当数组被用作decltype的参数时或者作为取地址符,sizeof及typeid(19.2.2节,732页)等运算符对象时,上述转换过程不会发生.同样的,如果用一个引用来初始化数组(3.5.1 102页),上述转换过程也不会发生,当在表达式中使用函数类型时会发生类似的指针转换(6.7节 221页)
    int arr[10];
    int *ptrs[10]; // ptrs是含有10个整型指针的数组
    int &refs[10]; //error,不存在引用的数组
    int (*Parray)[10] = &arr;  //Parray指向一个含有10个整数的数组,用法在下面
    int (&arrRef)[10] = arr;   //arrRef引用一个含有10个整数的数组,用法在下面

    int a[10] = {1,2,3};
    int (&ptr)[10] = a;  //相当于a的别名是ptr
    cout<<ptr[0]<<endl;


    int a[10] = {1,2,3};
    int (*ptr)[10] = &a;
    cout<<(*ptr)[0];  // === a[0]


    int a[2][10] = {1,2,3};
    int (*ptr)[10] = a;

指针的转换

  • 常量整数值0或者字面值nullptr能转换成任意指针类型
  • 指向任意非常量的指针能换成void*
  • 指向任意对象的指针能转换成const void*
  • 15.2.2(530页)

转换成布尔类型

  • 如果指针或者算术类型的值为0,转换结果为false,否则转换结果是true
char *cp=get_string();
if(cp) // 如果指针cp不是0,条件为真
while(*cp)  //如果*cp不是空字符,条件为真

转换成常量

  • 允许将指向非常量类型的指针转换成指向相应的常量类型的指针,对于引用也是这样.但是相反的转换并不存在,因为这试图删除底层的const

类类型定义的转换

  • 类类型能定义由编译器自动执行的转换,不过编译器每次只能执行一种类类型的转换.
string s,t = "a value"; //字符串转换成string类型.
while( cin>>s)      

4.11.3 显示转换

首先必须明白:强制类型转换非常危险

命名的强制类型转换

static_cast

  • 任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast
  • static_cast的常用情景:将一个较大的算术类型赋值给较小的类型
  • 有时可以使用static_cast找回存在于void*中的指针
void *p = &d; //正确:任何非常量对象的地址都能存入void*
double *dp = static_cast<double*>(p);
//正确:将void*转换回初始的指针类型

const_cast

  • const_cast只能改变运算对象的底层const
const char *pc;
char *p = const_cast<char*>(pc);
//正确:但是通过p写值是未定义的行为
  • 去掉性质:将常量对象转换成非常量对象的行为.
  • 只有const_cast能改变表达式的常量属性
const char *cp;

char *q = static_cast<char*>(cp);
//error:只有const_cast才能去掉const属性

static_cast<string>(cp);
//正确:字符串字面值转换成string类型
const_cast<string>(cp);
//error:const_cast只能改变常量属性
  • const_cast常常用于函数重载的上下文中(6.4节,208也下面所示)
const string & shorterString(const string &s1,const string s2)
{
    return s1.size() <= s2.size() ? s1:s2;
}

上面的函数对于常量调用好着,但是两个非常量对象调用却返回常量调用

const string & shorterString(const string &s1,const string s2)
{
    return s1.size() <= s2.size() ? s1:s2;
}
// 上面的函数对于常量调用好着,但是两个非常量对象调用却返回常量调用

string & shorterString( string &s1, string s2)
{
    auto &r = shorterString(const_cast<const string&>(s1),
                            const_cast<const string&>(s2));
    return const_cast<string&>(r);
}

reinterpret_cast

  • 为运算对象的位模式提供较低层次上的解释
int *ip;
char *pc = reinterpret_cast<char*>(ip);
//语法上正确,但是非常危险

在这里插入图片描述

4.12运算符优先级表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值