• C++ Primer学习笔记-----第四章:表达式


    表达式由一个或多个运算对象组成,对表达式求值将得到一个结果。

    4.1.基础:

    在表达式求值的过程中,运算对象常常由一种类型转换成另外一种类型。

    C++语言定义了运算符作用于内置类型和复合类型的运算对象是所执行的操作。当运算符作用于类类型的运算对象时,用户可以自行定义其含义,称之为重载运算符。

    左值右值从C语言继承过来的,原本为了帮助记忆:左值可以位于赋值语句左侧,右值则不能。
    C++中:
    当一个对象被用作右值的时候,用的对象的值(内容);
    当对象被用作左值的时候,用的是对象的身份(在内存中的位置)

    在需要右值的地方可以用左值来代替,但是不能把右值当成左值使用。

    常用的运算符要用的左值的:
    
    1.赋值运算符需要一个(非常量)左值作为其左侧运算对象,得到的结果也仍然是一个左值。
    2.取地址符作用于一个左值运算对象,返回一个指向运算对象的指针,这个指针是一个右值。
    3.内置解引用运算符、下标运算符、迭代器解引用运算符、string和vector的下标运算符的求值结果都是左值。
    4.内置类型和迭代器的递增递减运算符作用于左值运算对象,其前置版本所得的结果也是左值。
    
    *****************关键字decltype有所不同*******************
    如果表达式的求值结果是左值,decltype作用于该表达式(不是变量)得到一个引用类型;
    举例:
    假定p的类型是int*,因为解引用运算符生成左值,所以decltype(*p)的结果是int&。
    另一方面,因为取地址运算符生成右值,所以decltype(&p)的结果是int**,指向整型指针的指针。
    
    关于decltype(&p)的结果是int**,我的理解是decltype(p)的结果是int*,因为p是int类型的指针,
    在对指针取地址运算decltype(&p),得到的就是指针的指针。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    优先级:不确定的情况加括号即可

    求值顺序:

    int i = f1() * f();		//无法知道到底是f1和f2哪个先调用
    
    int i = 0;
    cout << i << " " << ++i << endl;	//同样这里的结果未知
    
    • 1
    • 2
    • 3
    • 4

    有4种运算符明确规定了运算符的求值顺序:

    1.逻辑与:&&,先求左侧运算对象的值,左侧为真时才求右侧的
    2.逻辑或:||,同上
    3.条件运算符:?:
    4.逗号运算符:,
    
    • 1
    • 2
    • 3
    • 4

    运算对象的求值顺序与优先级和结合律无关

    例如:f()+g()*h()+j()
    1.优先级规定,g()的返回值和h()的返回值相乘
    2.结合律规定,f()的返回值先与g()h()的乘积相加,再与j()的返回值相加
    3.对于这些函数的调用顺序没有明确规定
    
    ***********************************************
    如果f、g、h、j是无关函数,它们既不会改变同一个对象的状态也不执行IO任务,那么调用顺序不受限制。
    反之,如果其中某几个函数影响同一个对象,则它是一条错误的表达式,将产生未定义的行为。
    ***********************************************
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    建议:
    在这里插入图片描述

    4.2.算术运算符

    算术运算符的运算对象和求值结果都是右值

    m%(-n) 等于m%n,(-m)%n等于-(m%n)
    -21%-8 = -5;
    21%-5 = -1;

    4.3.逻辑和关系运算符

    值为0的运算对象表示假,否则表示真。

    4.4.赋值运算符

    赋值运算符的左侧运算对象必须是一个可修改的左值

    赋值运算满足右结合律
    int a,b;
    a=b=0;

    4.5.递增和递减运算符
    在这里插入图片描述
    在这里插入图片描述
    4.6.成员访问运算符
    ptr->mem 等价于 (*ptr).mem
    解引用的优先级低于点运算符

    4.7.条件运算符
    cond ? expr1 : expr2 ;

    4.8.位运算符
    左移:<<
    右移:>>
    按位与:&
    按位或:|
    按位异或:符合打不出来
    按位取反:~

    4.9.sizeof运算符
    sizeof(type)
    sizeof expr

    求数组的大小:

    int a[] = {1,3,3};
    auto length = sizeof(a)/sizeof(*a);
    
    • 1
    • 2

    4.10.逗号运算符

    逗号运算符经常被用在for循环中
    首先对左侧的表达式求值,然后将求值结果丢弃。
    逗号运算符的真正的结果是右侧表达式的值。
    如果右侧运算对象是左值,那么最终的求值结果也是左值。

    vector<int> vec;
    auto cnt=vec.size();
    for(auto i=0;i!=vec.size();++i,--cnt)
    {
    	vec[i]=cnt;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.11.类型转换
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    其他隐式类型转换

    1.数组转换成指针:在大多数用到数组的表达式中,数组自动转换成指向数组首元素的指针
    	当数组被用作decltype关键字的参数,或者作为取地址符(&)、sizeoftypeid等运算符的运算对象是,上述转换不会发生。
    2.指针的转换
    	常量整数0或者字面值nullptr能转换成任意指针类型
    	指向任意非常量的指针能转换成void*
    	指向任意对象的指针能转换成const void*
    3.转换成布尔类型
    	如果指针或算术类型的值为0,转换结果是false;否则转换结果是true
    4.转换成常量
    	指向非常量类型的指针转换成指向相应的常量类型的指针,引用同理
    5.类类型定义的转换
    	由编译器自动执行的转换
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    显示转换

    cast-name<type>(expression)
    type是转换的目标类型,expressioon是要转换的值,如果type是引用类型,结果是左值。
    cast-name是:static_castdynamic_castconst_castreinterpret_cast中的一种
    
    1.static_cast:
    	任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast
    	double d=static_cast<double>(j)/i;
    	
    	static_cast对于编译器无法自动执行的类型转换也非常有用。可以使用static_cast找回存在于void*指针中的值
    	int a=3;
    	void* p=&a;
    	int *ptr=static_cast<int*>(p);
    2.const_cast:
    	const_cast只能改变运算对象的底层const.
    	const char *pc;
    	char *p = const_cast<char*>(pc);
    	只要const_cast能改变表达式的常量属性
    	const char *cp;
    	static_cast<string>(cp);	//正确,字符串字面值转换成string类型
    3.reinterpret_cast:
    	reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述
    旧式的强制类型转换

    type (expr)		//函数形式的强制转换
    (type)expr		//C语言风格的强制转换
    
    根据所涉及的类型不同,旧式的强制类型转换分别具有与
    
    • 1
    • 2
    • 3
    • 4

    优先级表
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    ControllerBeanNameHandlerMapping类功能简介说明
    day46:C++ day6 继承过程中的特殊成员函数、多重继承、虚继承、多态、泛型编程模板
    qt 汉字输出 中文输出 显示乱码 qDebug() 乱码 解决
    小学语文 - 朗读
    java 连接SSH工具操作服务器 (构建者模式+Util类) 分享
    从零开始运行YOLOV5
    [免费专栏] ATTACK安全之车机(Android)设备中监控命令执行的一些想法【概念篇】
    Android端Base64解码表情emoj乱码
    Elasticsearch - DSL 查询语句
    【复旦邱锡鹏教授《神经网络与深度学习公开课》笔记】卷积
  • 原文地址:https://blog.csdn.net/weixin_41155760/article/details/125599354