Archive for 19 4 月, 2010

C++ Primer Chapter5

星期一, 19 4 月, 2010

1、表达式由一个或多个操作数通过操作符组合而成。每个表达式都会产生一个结果。如果表达式中没有操作符,则其结果就是操作数本身的值。对于含有操作符的表达式,它的值通过对操作数做指定操作获得。除了特殊用法外,表达式的结果是右值,可以读取该结果值,但是不允许对它进行赋值。

2、如果两个操作数都是负数,求模操作的结果则为负数(或零);如果只有一个操作数为负数,除法操作和求模操作的结果取决于机器。

3、对于位操作符,由于系统不能确保如何处理其操作数的符号位,所以强烈建议使用unsigned整型操作数。

4、赋值操作符的左操作数必须是非const的左值。数组名是不可修改的左值:因此数组不可用作赋值操作的目标。

与下标和解引用操作符一样,赋值操作符也返回左值。

5、点操作符用户获取类类型对象的成员。

6、sizeof操作符的作用是返回一个对象或类姓名的长度,返回值的类型为size_t,长度的单位是字节。参考资料:sizeof

7、逗号表达式的结果是其最右边表达式的值。

8、只有当操作符的两个操作数涉及到同一个对象,并改变其值时,操作数的计算次序才会影响结果。

9、如果不提供显示初始化,动态创建的对象与在函数内定义的变量初始化方式相同。对于类类型的对象,用该类的默认构造函数初始化;而内置类型的对象则无初始化。

一旦删除了指针所指向的对象,立即将指针置为0,这样就非常清楚地表明指针不再指向任何对象。

如果其他动态对象一样,const动态对象也是使用删除指针来释放的。

10、对于包含signed和unsigned int型的表达式,其转换可能出乎我们的意料。表达式中的signed型数值会被转换为unsigned型。

11、不将数组转换为指针的例外情况有:数组用作取地址(&)操作符的操作数或sizeof操作符的操作数时,或用数组对数组的引用进行初始化时,不会将数组转换为指针。参考资料:C++ Primer Chapter4

12、命名的强制类型转换符号的一般形式如下:

cast-name<type>(expression)

其中cast-name为static_cast、dynamic_cast、const_cast和reinterpret_cast之一,type为转换的目标类型,而expression则是被强制转换的值。强制转换的类型指定了在expression上执行某种特定类型的转换。

dynamic_cast支持运行时识别指针或引用所指向的对象。

const_cast将转换掉表达式的const性质。只有使用const_cast才能将const性质转换掉。在这种情况下,试图使用其他三种形式的转换都会导致编译时的错误。类似地,除了添加或删除const特性,用const_cast符来执行其他任何类型转换,都会引起编译错误。

static_cast编译器隐式执行的任何类型转换都可以由它显示完成。(尝试转换一个对象的类型到另一个无关的类型将失败。)

reinterpret_cast通常为操作数的位模式提供较低层次的重新解释。(总是成功的“欺骗”编译器:转换一个对象的类型到另一个无关的类型。)

参考资料:reinterpret_cast

static_cast和reinterpret_cast的区别

reinterpret_cast的本质(转)

C++ Primer Chapter4

星期一, 19 4 月, 2010

1、数组是由类型名、标识符和维数组成的复合数据类型,是一种存储单一数据类型对象的容器,其中每个对象都没有单独的名字。

没有所有元素都是引用的数组。

数组的维数必须用值大于等于1的常量表达式。此常量表达式只能包含整型字面值常量(如10)、枚举常量或者常量表达式初始化的整型const对象。非const对象以及要到运行阶段才知道其值的const变量都不能用于定义数组的维数。

除非显示地提供元素初值,否则内置类型的局部数组的元素没有初始化。

显示初始化的数组不需要指定数组的维数值(不完整类型),编译器会根据列出的元素个数来确定数组的长度。

2、指针的概念很简单:指针用于指向对象。具体来说,指针保存的是另一个对象的地址。

标准翻译版:一个指针类型可能来自于一个函数类型、一个对象类型或一个不完整的类型,以上统称为被引用类型。一个指针类型描述了一个对象,它的值提供了到一个被引用类型实体的引用。

参考资料:解密数组名本质

数组与指针的艺术——深入探索C/C++数组与指针的奥秘

若指针保存0值,表明它不指向任何对象。(把int型变量赋给指针是非法的,尽管此int型变量的值可能为0。)

如果必须分开定义指针和其所指向的对象,则将指针初始化为0。因为编译器可检查测出0值的指针,程序可判断该指针并未指向一个对象。

3、指针和引用有两个重要区别:第一个区别在于引用总指向某个对象:定义引用时没有初始化是错误的。第二个重要区别则是赋值行为的差异:给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化,就始终指向同一个特定对象(这就是为什么引用必须在定义时初始化的原因)。

4、在表达式中使用数组名时,该名字会自动转换为指向数组第一个元素的指针(左值转换成右值)。当数组名作为数组对象定义的标识符、初始化器以及作为sizeof、&的操作数时,代表数组对象本身。

数组名不是指针。数组名的内涵在于其指代实体是一种数据结构(数组);数组名的外延在于其可以转换为指向其指代实体的指针;指向数组的指针则是一种变量类型,仅仅意味着数组的存放地址。

5、使用下标访问数组时,实际上是使用下标访问指针。

C++允许计算数组或对象的超出末端的地址,但不允许对此地址进行解引用操作。而计算数组超出末端的位置之后或数组首地址之前的地址都是不合法的。

C++语言强制要求指向const对象的指针也必须具有const特性:

const typename *ptr;    // 指向typename类型const对象的指针

typename *const ptr;    // const指针

不能使用指向const对象的指针修改基础对象,然而如果该指针指向的是一个非const对象,可用其他方法修改其所指的对象。

如果把指向const的指针理解为“自以为指向const的指针”,这可能会对理解有所帮助。

6、typedef string *pstring;

const pstring cstr;

声明const pstring时,const修饰的是pstring的类型,这是一个指针。因此,该声明语句应该是把cstr定义为指向string类型对象的cosnt指针,这个定义等价于:

string *const cstr;

7、字符串字面值的类型就是const char类型的数组。

C++虽然不允许定义长度为0的数组变量,但明确指出,调用new动态创建长度为0的数组是合法的。用new动态创建长度为0的数组时,new返回有效的非零指针。该指针与new返回的其他指针不同,不能进行解引用操作,因为它毕竟没有指向任何元素。

c_str返回的数组(const char [])并不保证一定是有效的,接下来对st2的操作有可能会改变st2的值,使刚才返回的数组失效。如果程序需要持续访问该数据,则应该复制c_str函数返回的数组。

8、严格地说,C++中没有多维数组,通常所指的多维数组其实就是数组的数组。

多维数组转换而成的指针类型应该是指向第一个内层数组的指针。

9、typedef int int_array[4];

int_array *ip = ia;    // int_array指针指向包含四个int元素的数组一行

10、ptrdiff_t与size_t类型一样,也是一种与机器相关的类型,在cstddef头文件中定义。size_t是unsigned类型,而ptrdiff_t则是signed整型。