您的位置:首页 > 编程语言 > C语言/C++

《More Effective C++》读书笔记-基础议题

2016-04-30 14:56 309 查看

一、仔细区别 pointers 和 references

1)引用不可以为空(必须指向某个对象),而指针可以为空。

引用带来的好处:不需要检查空引用,也就省了相应的处理代码

指针在使用前则需要判断是否为空,对应两种处理逻辑。

2)引用必须要初始化,而指针不是必要的(但最好初始化)。

3)指针可以被重复赋值,指向另一个对象;引用总是指向(代表)它最初获得的那个对象。

4)重载某个操作符(例如operator[])的时候,必须返回某种“能够被当做assignment赋值对象”的东西:引用。若使用指针会造成语义误解。

总结:

1)使用指针:一是存在不指向任何对象的可能性;二是需要能够在不同的时刻指向不同的对象。

2)使用引用:总是指向一个对象且一旦指向一个对象之后就不会改变指向;重载某个操作符时。

另附其他款项:

相同点:都是地址的概念。指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。

不同点:

1)指针是一个实体,而引用仅是个别名;

2)引用没有 const,指针有 const,const 的指针不可变;

3)指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)

4)”sizeof引用”得到的是所指向的变量(对象)的大小,而”sizeof指针”得到的是指针本身的大小。

二、尽量使用C++风格的类型转换

1、static_cast(常规类型转换):

功能上基本上与C风格的类型转换一样强大,限制也一样。

1)不能把struct转换成int类型,或者把double类型转换成指针类型。

2)它不能从表达式中去除const属性

使用方式形如:

static_cast<type>(expression),如:int d = static_cast<int>(3.14);


2、const_cast(去常量转换):

用来改变表达式中的常量性(constness)或变易性(volatileness)。但是不能用它来完成修改这两个属性之外的事情。

3、dynamic_cast(继承转换):

1)用来执行继承体系中“安全的向下转型或跨系转型动作”。失败的转换将返回空指针或者抛出异常。

2)想要使用 dynamic_cast ,基类中必须有虚函数。也就是必须要涉及继承机制。

用来针对一个继承体系做向下的安全转换,目标类型必须为指针或者引用。基类中要有虚函数,否则会编译出错;static_cast则没有这个限制。原因是:存在虚函数,说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义。由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表。必须保证源类型跟目标类型本来就是一致的,否则返回 null 指针。这个函数使用的是RTTI机制,所以编译器必须打开这个选项才能编译。

4、reinterpret_cast(函数指针转换):

最常用的用途是转换函数指针类型。不具有移植性。

三、绝对不要以多态方式处理数组

多态和指针算术不能混合在一起使用,所以数组和多态也不能用在一起。

数组中各元素的内存地址是数组的起始地址加上之前各个元素的大小得到的,如果各元素大小不一,那么编译器将不能正确地定位元素,从而产生错误。

比如,array[i] 其实是一个指针算术表达式的简写,它代表的其实是
*(array+i)
,array是一个指向数组起始处的指针。在 for 里遍历 array 时,必须要知道每个元素之间相差多少内存,而编译器则根据传入参数来计算得知为 sizeof(Base),而如果传入的是派生类数组对象,它依然认为是 sizeof(Base),除非正好派生类大小正好与基类相同,否则运行时会出现错误。

四、避免无用的缺省构造函数(default constructors)

没有缺省构造函数造成的问题:通常不可能建立对象数组,对于使用非堆数组,可以在定义时提供必要的参数。另一种方法是使用指针数组,但是必须删除数组里的每个指针指向的对象,而且还增加了内存分配量。

提供无意义的缺省构造函数会影响类的工作效率,成员函数必须测试所有的部分是否都被正确的初始化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: