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(p); // 注意,若d不是double,会error
    
    1. const_cast:用于cast away low-level const;在重载函数场景下最有用
    const char *pc;
    char *p = const_cast(pc); // ok: 但若pc指向的是一个const对象,那么writing through p is undefined
    
    const char *cp;
    // error: static_cast can't cast away const
    char *q = static_cast(cp);
    static_cast(cp); // ok: converts string literal to string
    const_cast(cp); // error: const_cast only changes constness
    
    1. reinterpret_cast:reinterprete bits;【通常很危险】;用在任意指针(或引用)类型之间的转换;以及指针与足够大的整数类型之间的转换;从整数类型(包括枚举类型)到指针类型,无视大小
    int *ip;
    char *pc = reinterpret_cast(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.

操作符优先级



你可能感兴趣的:(C++ primer 第四章-表达式)