C++primer学习笔记《4》

每一个表达式都有一个结果,字面值常量也是表达式,其结果就是值本身。除了特殊用法外表达式的结果是右值。是左值的情况也有,比如++i;这个表达式就是一个左值;还有逗号运算符的结果是表达式最右侧操作符德值,如果最右是一个左值的话,那整个逗号表达式就是左值。

表达式涉及到操作符和操作数,操作符有优先级规则,有结合性,还有操作数的求值顺序。就操作数的求值顺序而言,比如f1() * f2();两个函数的返回值进行相乘,但无法确定先调用哪个函数。

操作符%成为“求余”或是“取模”,操作数为整型,其中bool类型也可以。

对于“%”和“/”这两个操作符来说。如果只有一个操作数为负数,那这两种操作的结果(这里仅指绝对值,不考虑符号)都是取决于机器的;取模运算的符号也是取决机器的;但除法操作的结果肯定是负数。举个例子:

21/ -5:依赖机器的,结果是-4或是-5

21% -5:依赖机器的,对应的结果是1或是-4

在逻辑表达式中,逻辑与和逻辑或总是先计算左操作数,再计算右操作数。只有在仅靠左操作数无法判断表达式结果时,才会求解器右操作数。我们称这种运算原则为“短路求值”。

相等测试与bool字面值。由于bool中的true可以转换为1,所以如何判断某值与true相等却成了难题。这里要考虑某值val的类型,如果val是bool类型的,那么正确的判断就是if ( val ) { … };即可。如果val不是bool类型,那判断就和if ( val ==1 ) {…};等价了;假如val是整型,那if ( val )则是当且仅当val为0时为逻辑假,其余的值,无论正负都是逻辑真。

位操作符的操作数是整型,这里的整型不仅可以是正整数,也可以是负整数。但对于负整数的符号位处理方式,不同的机器有着不同的实现,所以尽量使用无符号正整数来作为位运算的操作数。

位运算中的左移和右移操作原则。无符号来说,左移是数值扩大,右侧补0;右移是数值减小,左侧补0。对于有符号来说,其右移过程中,左侧可能是补0将其变成正数,也可能补1不改变其符号,这都依赖于机器。

Cout<<42 + 10;正确,因为+高于<<

Cout<<(10 < 42);也正确,因为有括号

Cout<<10 < 42;错误,因为<<高于关系运算符。Cout<<10之后返回一个ostream的引用,返回引用的目的是可以连续输出,达到流的效果。将一个ostream引用和42对比较是无意义的。

赋值操作的右结合性。

Intival, jval;  ival = jval = 0;这是合法的。赋值运算符也有返回值,先执行jval= 0,返回一个整型再赋给ival。赋值运算符具有很低的优先级。

判等和赋值容易出错的地方。If ( i = 42 )这句话实际上是对的,字面解释是把42赋给i,然后判断i的真或假。但这显然是无意义的,这句代码像是被写错的,原意是if ( i== 42 )。为了能避免这样的隐蔽错误,可以写成if ( 42 == i)这样一来,假如少写了个“=”if( 42 = i )就是编译错误,可以及时发现。

关于如何交换两个数的值.

算术方法:a = a + b;  b = a – b;  a = a – b;

位运算方法: a ^= b;  b ^= a;  a ^= b;

对于i++和++i的更深层次讨论,在一个长的表达式中有多个关于i的自增和自减操作,这样的表达式的结果是依赖机器的。这里面有一个概念是任何语言的表达式求值都逃不掉的,那就是序点。序点直观来说就是当执行到此序点时必须保证序点前的子表达式已经求出结果。在C++中规定,上一个和下一个序点之间,对象的值至多被修改1次。至于规定表达式中的哪些地方设置序点,这有机器实现决定。值得一说的是在长表达式中不要试图多次对一个对象修改。

I++是右值,++i是左值。

I++的具体实现:

Constint int::operator++(int)

{

IntoldValue = *this;

++(*this);

ReturnoldValue;

}

++i的实现细节:

Int&int::operator++()

{

*this+= 1;

Return*this;

}

时间: 2024-11-03 01:34:03

C++primer学习笔记《4》的相关文章

C++Primer学习笔记《三》

数组名其实就是一个常指针,指向数组元素中第一个的地址,在程序中如果要用指针遍历数组,不能直接用数组名来自增或自减,因为它是常量,一般先把数组名保存一份同类型的指针,然后再用这个指针来自增或是自减来实现遍历. 指针也是可以进行算术加法和减法的,但必须保证原地址和结果地址都是想同一个数组的元素或是指向数组的末端元素的下一个单元(类似end()). 指针的减法操作是有意义的,它表示两个指针的相对位置关系,减法结果是ptrdiff_t类型,和size_t类型一样,是一种机器相关的类型,size_t是无符

C++ Primer学习笔记(三) C++中函数是一种类型!!!

C++中函数是一种类型!C++中函数是一种类型!C++中函数是一种类型! 函数名就是变量!函数名就是变量!函数名就是变量! 重要的事情要说三遍... 接 C++ Primer学习笔记(二) 类的构造函数 与类同名,且无返回类型. 同类的成员函数一样,也可以在类中声明,在类外定义. 格式: 类名(): 成员1(成员1初始化值), 成员2(成员2初始化值) { } 以上,冒号至大括号中间的部分,称为构造函数的初始化列表,用于调用类成员的构造函数来初始化. 没有在初始化列表中显式指定初始化的成员,将会

C++ Primer学习笔记32_面向对象编程(3)--继承(三):多重继承、虚继承与虚基类

C++ Primer学习笔记32_面向对象编程(3)--继承(三):多重继承.虚继承与虚基类 一.多重继承 在C++语言中,一个派生类可以从一个基类派生,称为单继承:也可以从多个基类派生,称为多继承. 多重继承--一个派生类可以有多个基类 class <派生类名> : <继承方式1> <基类名1>,<继承方式2> <基类名2>,... { <派生类新定义成员> }; 可见,多继承与单继承的区别从定义格式上看,主要是多继承的基类多于一个

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr)、C++对象模型

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr).C++对象模型 一.虚函数表指针(vptr)及虚基类表指针(bptr) C++在布局以及存取时间上主要的额外负担是由virtual引起的,包括: virtual function机制:用以支持一个有效率的"执行期绑定": virtual base class:用以实现多次在继承体系中的基类,有一个单一而被共享的实体. 1.虚函数表指针 C++中,有两种数据

C++ Primer 学习笔记_98_特殊工具与技术 --优化内存分配

特殊工具与技术 --优化内存分配 引言: C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象.new表达式自动运行合适的构造函数来初始化每个动态分配的类类型对象. new基于每个对象分配内存的事实可能会对某些类强加不可接受的运行时开销,这样的类可能需要使用用户级的类类型对象分配能够更快一些.这样的类使用的通用策略是,预先分配用于创建新对象的内存,需要时在预先分配的内存中构造每个新对象. 另外一些类希望按最小尺寸为自己的数据成员分配需要的内存.例如,

C++ Primer 学习笔记_73_面向对象编程 --再谈文本查询示例

面向对象编程 --再谈文本查询示例 引言: 扩展第10.6节的文本查询应用程序,使我们的系统可以支持更复杂的查询. 为了说明问题,将用下面的简单小说来运行查询: Alice Emma has long flowing red hair. Her Daddy says when the wind blows through her hair, it looks almost alive, like a fiery bird in flight. A beautiful fiery bird, he

C++ Primer 学习笔记_19_类与数据抽象(5)_初始化列表(const和引用成员)、拷贝构造函数

C++ Primer 学习笔记_19_类与数据抽象(5)_初始化列表(const和引用成员).拷贝构造函数  从概念上将,可以认为构造函数分为两个阶段执行: 1)初始化阶段: 2)普通的计算阶段.计算阶段由构造函数函数体中的所有语句组成. 一.构造函数初始化列表 推荐在构造函数初始化列表中进行初始化 1.对象成员及其初始化 <span style="font-size:14px;">#include <iostream> using namespace std;

C++ Primer 学习笔记_102_特殊工具与技术 --运行时类型识别[续]

特殊工具与技术 --运行时类型识别[续] 三.RTTI的使用 当比较两个派生类对象的时候,我们希望比较可能特定于派生类的数据成员.如果形参是基类引用,就只能比较基类中出现的成员,我们不能访问在派生类中但不在基类中出现的成员. 因此我们可以使用RTTI,在试图比较不同类型的对象时返回假(false). 我们将定义单个相等操作符.每个类定义一个虚函数 equal,该函数首先将操作数强制转换为正确的类型.如果转换成功,就进行真正的比较:如果转换失败,equal 操作就返回 false. 1.类层次 c

C++ Primer 学习笔记_99_特殊工具与技术 --优化内存分配[续1]

特殊工具与技术 --优化内存分配[续1] 三.operator new函数和operator delete 函数 – 分配但不初始化内存 首先,需要对new和delete表达式怎样工作有更多的理解.当使用new表达式 string *sp = new string("initialized"); 的时候,实际上发生三个步骤: 1)首先,表达式调用名为operator new 的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的一个对象; 2)接下来,运行该类型的一个构造函数

C++ Primer 学习笔记_81_模板与泛型编程 --类模板成员[续1]

模板与泛型编程 --类模板成员[续1] 二.非类型形参的模板实参 template <int hi,int wid> class Screen { public: Screen():screen(hi * wid,'#'), cursor(hi * wid),height(hi),width(wid) {} //.. private: std::string screen; std::string::size_type cursor; std::string::size_type height