天天看点

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

4、1 基础

4.1.1 基本概念

1、左值和右值

(1)C++的表达式要不然是右值(rvalue),要不然就是左值(lvalue)

(2)一个重要原则:在需要右值的地方可以用左值来替代,但不能把右值当成左值使用(有一种情况例外,可以把右值当成左值使用)。

(3)当一个对象被用作右值的时候,用的对象的值(内容),当对象被用作左值的时候,用的是对象的身份(在内存中的位置)

(4)需要用到左值的运算符

①赋值运算符(需要一个非常量左值)

②取地址符

③内置解引用运算符、下标运算符。

④内置类型和迭代器的递增减运算符

4.1.2 优先级与结合律

1、复合表达式(compound expression):是指含有两个或多个运算符的表达式。

(1)括号可以无视优先级和结合律。

4.1.3 求值顺序

1、有四种运算符明确规定了运算符对象的求值顺序

(1)&&

(2)||

(3)?:

(4),

4.3节练习

4.10:为while循环写一个条件,使其从标准输入中读取整数,遇到42时候停止。

int a;
    while (cin >> a&&a != )
        cout << a << endl;
           

4.11:书写一条表达式用于测试4个值a、b、c、d的关系,确保a大于b、b大于c、c大于d

int a = , b = , c = , d = ;
    if (a > b&&b > c&&c > d)
        cout << "a>b,b>c,c>d" << endl;
           

4.4 赋值运算符

1、赋值运算符满足右结合律

2、赋值运算表达式优先级比较低,所以在条件语句中,赋值部分通常应该加上括号。

4.5 递增和递减运算符

1、

(1)前置版本(++i):先将运算对象加(减1),然后将改变后的对象作为求值结果。

(2)后置版本(i++):先将对象作为求值结果,再给运算对象加1(或减1)

2、运算对象可按任意顺序求值

4.7条件运算符

1、格式:

(1)condition为真,执行expr1

(2)condition为假,执行expr2

2、条件运算符可嵌套

3、条件运算符的优先级非常低,因此当一条长表达式中嵌套了(?:),通常需在两端加上括号。

4、7节练习

4.21:编写一段程序,使用条件运算符从vector中找到哪些元素的值是奇数,然后将这些奇数值

int a;
    std::vector<int> iv;
    while(cin>>a)
        iv.push_back(a);
    for(auto:vi)
        cout<<((i%==)?:i*);
           

4.22:用条件运算符版本将学生成绩分为fail、low pass、pass、high pass四个阶层。

int grade;
    cout<<"Enter grade:\n";
    cin>>grade;
    cout<<(grade<?"fail":(grade<?"low pass":(grade<?"pass":"high pass")))<<endl;
           

用if语句写的版本

int grade;
    cout<<"Enter grade: ";
    cin>>grade;
    if(grade<)
        cout<<"fail"<<endl;
    else if(grade<&&grade>)
        cout<<"low pass"<<endl;
    else if(grade>&&grade<)
        cout<<"pass"<<endl;
    else
        cout<<"high pass"<<endl;
           

4.8 位运算符

1、位运算符作用于整数类型的运算对象,并把运算对象看成是二进制的集合。

(1)位运算符提供检查和设置二进制位的功能

2、bitset类型,其标准库类型也可以表示任意大小的二进制位集合。

3、位运算符(满足左结合律)

(1)~(位求反)

<1>格式:

~expr

(2)<<(左移) >>(右移)

<1>格式:

expr1<<expr2

expr1>>expr2

(3)&(位与)

<1>格式:

expr1&expr2

(4)^(位异或)

<1>格式:

expr^expr

(5)|(位与)

<1>格式:

expr|expr

4、位运算符(又叫IO运算符)满足左结合律

4.9 sizeof运算符

1、作用:返回一条表达式或一个类型名所占的字节数

2、格式:

(1)

sizeof (type);
size expr;
           

3、sizeof运算符可获取类成员大小而无须提供一个具体的对象。

4.11 类型转换 ##

1、隐式转换(implicit conversion):由编译器自动执行的类型转换(自动执行,无须程序员介入。)

2、发生隐式转换的情况

(1)比int类型小的整型值受限提升为较大的整数类型

(2)在条件中,非布尔值转换成布尔类型

(3)初始化过程中,初始值(literal)转换成变量类型

(4)赋值语句中,右侧运算符转换成左侧运算符

(5)算术运算符或关系运算符有多种类型的时候

(6)函数调用的时候

4.11.3 显式转换

1、命名的强制类型转换(cast)

(1)格式: cast-name(expression)

<1>type:转换的目标类型

<2>expression:要转换的值

<3>type若是引用类型,则结果是左值

<4>cast-name是以下4种类型

①static_const

②dynamic_cast

③const_cast

④reinterpret_cast

中的一种

(2)static_cast:任何具有明确定义的类型转换,只要不包含底层const,都可以使用。

<1>例:

double slope=static_cast<double>(j)/i;
           

<2>优点:较大算术类型转换为较小算术类型。

(3)const_cast:只能改变运算对象的底层const

<1>例:

const char c='k';
char *pc=&c;
char *p=const_cast<char *>(pc);
//正确,但是通过p写值是未定义的行为 
           

<2>优点:const_cast能去掉底层const,将一个指向常量的指针转换为一个指向不一定是常量的指针。

(4)reinterpret_cast:通常为运算对象的位模式提供较低层次上的重新解释(一般用于不同类型的指针转换)

<1>例:

int *ip;
char *pc=reinterpret_cast<char *>ip;
//pc所指向的对象为int而非字符
string str(pc);     //运行时发生错误   
           

2、旧式的强制类型转换

(1)格式:

type(expr);     //函数形式的强制类型转换
(type)expr;     //C风格的强制类型转换
           

4.11.3节练习

4.36:假设i是int类型,d是double类型,书写表达式i*=d使其执行整数类型的乘法而非浮点类型的乘法

int i=;
    double d=;
    i*=static_cast<double>(d);
    i*=d;
    cout<<i<<endl;
           

4.37:用命名的强制类型转换改写下列旧式的转换语句

int i;
double d;
const string *ps;
char *pc;void *pv;

(a)pv=(void *)ps;
    pv=static_cast<void *>(const_cast<string *>(ps));

(b)i=int(*pc);
    i=static_cast<int>(*pc);

(c)pv=&d;
    pv=static_cast<void *>(&d);

(d)pc=(char *)pv;
    pc=static_cast<char *>(pv);
           

继续阅读