C++ primer 第四章-表达式

Hi!这里是山幺幺的c++ primer系列。写这个系列的初衷是,虽然在学校学习了c++,但总觉得对这门语言了解不深,因此我想来啃啃著名的c++ primer,并在这里同步记录我的学习笔记。由于我啃的是英文版,所以笔记是中英文夹杂的那种。另外由于已有一定的编程基础,所以这个系列不会含有太基础的知识,想入门的朋友最好自己啃书嘻嘻~

关于基础知识


左值与右值

  • C++中的每个表达式都是左值或者右值
  • When we use an object as an rvalue, we use the object’s value (its contents). When we use an object as an lvalue, we use the object’s identity (its location in memory).
  • 一般左值可以当作右值使用,右值无法当作左值使用
  • 取地址符 & 返回的指针是右值
  • 右值是const型
  • 返回左值的:built-in dereference、built-in subscript operators、iterator dereference、string and vector subscript operators等
  • 表达式使用decltype时,若表达式为左值,则结果为引用,若表达式为右值,则结果为指针,比如:decltype(*p) 为 int&,而decltype(&p) 为 int**
  • ++i 返回左值,i++ 返回右值(a copy of the object’s original value)
  • ptr->x 返回左值,a.x 返回左值(若a为左值)或右值(若a为右值)

关于操作符


运算符的顺序

  • 无法确定顺序的情形:
int i = f1() * f2(); // we have no way of knowing whether f1 will be called before f2 or vice versa

int i = 0;
cout << i << " " << ++i << endl; // undefined,可能是1 1或0 1或其他

*beg = toupper(*beg++); // error: this assignment is undefined,可能是以下任一种
*beg = toupper(*beg); 
*(beg + 1) = toupper(*beg); 
  • *pbeg++ 中,++比*优先级高

bool型最好不要参与算术运算

bool b = true;
bool b2 = -b; // b2 is true!
  • For most operators, operands of type bool are promoted to int. 所以 b2 = -b中,b = 1,b2 = -1

%和/

21 % 6; /* result is 3 */ 21 / 6; /* result is 3 */
21 % 7; /* result is 0 */ 21 / 7; /* result is 3 */
-21 % -8; /* result is -5 */ -21 / -8; /* result is 2 */
21 % -5; /* result is 1 */ 21 / -5; /* result is -4 */

关系运算符

int val = 2;
if (val == true) { /* ... */ } // false, true only if val is equal to 1!

赋值运算符

  • 初始化不是赋值!
  • 赋值运算符返回值是对左操作数的引用
  • 可以用list赋值
int k;
k = { 3 }; // ok
k = { 3.14 }; // error: narrowing conversion
  • 赋值运算符是右结合优先的
int ival, jval;
ival = jval = 0; // ok: each assigned 0

int ival, *pval; // ival is an int; pval is a pointer to int
ival = pval = 0; // error: cannot assign the value of a pointer to an int

string s1, s2;
s1 = s2 = "OK"; // string literal "OK" converted to string

cond ? expr1 : expr2

  • Result of the conditional operator is an lvalue if both expressions are lvalues or if they convert to a common lvalue type. Otherwise the result is an rvalue.
  • cout时记得加括号
cout << ((grade < 60) ? "fail" : "pass"); // prints pass
or fail
cout << (grade < 60) ? "fail" : "pass"; // prints 1 or 0! (cout返回true/false,所以不是error)
cout << grade < 60 ? "fail" : "pass"; // error: compares cout
to 60

位运算符

  • 使用位运算符时,最好用unsigned类型参与运算,因为signed类型的符号位处理是undefined的
  • 操作
  • <<:右边补0
  • >>:若为unsigned,左边补0;若为signed,可能补符号位,也可能补0
  • ~:取反,注意:对char取反时,char会转化为int,高位补0,取反后补的0都会变为1

sizeof

  • 返回size_t,是一个常表达式类型,所以可以用来定义array大小
Sales_data data, *p;
sizeof(Sales_data); // size required to hold an object of type Sales_data
sizeof data; // size of data's type, i.e., sizeof(Sales_data)
sizeof p; // size of a pointer
sizeof *p; // size of the type to which p points, i.e., sizeof(Sales_data)
sizeof data.revenue; // size of the type of Sales_data's revenue member
sizeof Sales_data::revenue; // alternative way to get the size of revenue
  • Because sizeof does not evaluate its operand, it doesn’t matter that p is an invalid (i.e., uninitialized) pointer. Dereferencing an invalid pointer as the operand to sizeof is safe because the pointer is not actually used. sizeof doesn’t need dereference the pointer to know what type it will return.
  • 对array进行sizeof,返回array中元素个数*元素类型大小
  • 对string和vector进行sizeof,只返回它们固定部分的大小,不含与它们中的元素

  • expr1, expr2 的值等于expr2的值

类型转换


隐式类型转换

  • 栗子
int ival = 3.541 + 3; // the compiler might warn about loss of precision

PS:首先执行 3.541+3,为了保证精度,3由int转为double,因此结果是double;再对ival进行初始化,被初始化的对象类型优先,因此ival最后值为6

  • 隐式类型转换发生的情形:
    1. 在大多数表达式中,values of integral types smaller than int are first promoted to an appropriate larger integral type
    2. 在conditions中,nonbool表达式会转换为bool
    3. 在初始化中,被初始化的对象类型优先
    4. 在赋值语句中,等号右边类型转换为左边
    5. In arithmetic and relational expressions with operands of mixed types, the types are converted to a common type.
    6. 其他在第六章叙述

隐式类型转换的具体分类

  • Arithmetic Conversions
    1. Integral Promotions:bool, char, signed char, unsigned char, short, and unsigned short are promoted to int if all possible values of that type fit in an int. Otherwise, the value is promoted to unsigned int. The larger char types (wchar_t, char16_t, and char32_t) are promoted to the smallest type of int, unsigned int, long, unsigned long, long long, or unsigned long long in which all possible values of that character type fit.
    2. signed和unsigned参与一个运算,一般是signed转换为unsigned(如果signed对象has a larger type,则取决于机器中各类型的大小。If all values in the unsigned type fit in the larger type, then the unsigned operand is converted to the signed type. If the values don’t fit, then the signed operand is converted to the unsigned type.)
bool flag; char cval;
short sval; unsigned short usval;
int ival; unsigned int uival;
long lval; unsigned long ulval;
float fval; double dval;
3.14159L + 'a'; // 'a' promoted to int, then that int converted to long double
dval + ival; // ival converted to double
dval + fval; // fval converted to double
ival = dval; // dval converted (by truncation) to int
flag = dval; // if dval is 0, then flag is false, otherwise true
cval + fval; // cval promoted to int, then that int converted to float
sval + cval; // sval and cval promoted to int
cval + lval; // cval converted to long
ival + ulval; // ival converted to unsigned long
usval + ival; // promotion depends on the size of unsigned short and int
uival + lval; // conversion depends on the size of unsigned int and long
  • Array to Pointer Conversions
int ia[10]; // array of ten ints
int* ip = ia; // convert ia to a pointer to the first element

PS:当对array使用decltype、取地址、sizeof或typeid时,或初始化一个引用为array时,不会发生这种类型转换

  • Pointer Conversions
    0 和 nullptr 可以转换为任意类型的指针,指向任何 nonconst type 的指针可以转换为 void,任意类型的指针可以转换为 const void,15章中还会讲到另一种与继承有关的指针转换

  • Conversions to bool
    指针或arithmetic value转换为bool

  • Conversion to const

int i;
const int &j = i; // convert a nonconst to a reference to const int
const int *p = &i; // convert address of a nonconst to the address of a const
int &r = j, *q = p; // error: conversion from const to nonconst not allowed
  • Conversions Defined by Class Types
string s, t = "a value"; // character string literal converted to type string
while (cin >> s) // while condition converts cin to bool

PS:编译器一次只能处理一个class-type conversion

显式类型转换

  • Named Casts
    1. dynamic_cast:19章会讲
    2. static_cast:不与low-level const相关的转换都可以;常用于when a larger arithmetic type is assigned to a smaller type,告诉编译器我们不在乎精度损失
    void* p = &d; // ok: address of any nonconst object can be stored in a void*
    // ok: converts void* back to the original pointer type
    double *dp = static_cast<double*>(p); // 注意,若d不是double,会error
    
    1. const_cast:用于cast away low-level const;在重载函数场景下最有用
    const char *pc;
    char *p = const_cast<char*>(pc); // ok: 但若pc指向的是一个const对象,那么writing through p is undefined
    
    const char *cp;
    // error: static_cast can't cast away const
    char *q = static_cast<char*>(cp);
    static_cast<string>(cp); // ok: converts string literal to string
    const_cast<string>(cp); // error: const_cast only changes constness
    
    1. reinterpret_cast:reinterprete bits;【通常很危险】;用在任意指针(或引用)类型之间的转换;以及指针与足够大的整数类型之间的转换;从整数类型(包括枚举类型)到指针类型,无视大小
    int *ip;
    char *pc = reinterpret_cast<char*>(ip);
    
  • Old-Style Casts
char *pc = (char*) ip; // ip is a pointer to int

PS:When we use an old-style cast where a static_cast or a const_cast would be legal, the old-style cast does the same conversion as the respective named cast. If neither cast is legal, then an old-style cast performs a reinterpret_cast.

操作符优先级



最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352