百度网页搜索部高级工程师 我的微博:http://weibo.com/pengwh85
全部博文(45)
分类: C/C++
2009-11-11 15:40:43
条款1:区分指针和引用
当你知道要指代某个对象并且不会再指代其他的东西时,那就应该选择引用。当实现某些操作符的时候,如果这些操作符在语义上的要求使得指针不可行,此时仍然需要使用引用。其他情况下,应该使用指针。
条款2:优先考虑C++风格的类型转换
1) static_cast:与通用的C风格的类型转换类似,也有与C风格的类型转换同样的限制。不能去除一个表达式的const属性。
2) const_cast:用来去除掉一个表达式的const属性或volatile属性。
3) dynamic_cast:用来针对一个继承体系做向下或者横向的安全转换。也就是说,用dynamic_cast把指向基类的指针(或引用)转换成指向派生类或者基类的兄弟类的指针(或引用),而且同时可以知道转换是否成功。还可以用来找到一个对象在内存中的起始地址。空指针(当转换指针的时候)或者异常(当转换引用的时候)意味着转换失败。dynamic_cast仅限于帮助你操纵继承体系。它们不能用于那些没有虚函数的类型。
4) reinterpret_cast:最常见的用法是用来在函数指针之间进行类型转换。几乎是不可移植的,转换结果常常是由(编译器的)实现所定义的。应避免使用。
条款3:决不要把多态应用于数组
条款4:避免不必要的默认构造函数
没有默认构造函数,在三种情况下会出现问题:
1) 创建数组的时候,通常没有很好的方法可以指定数组元素的构造函数的参数。
2) 没有默认构造函数的类,无法作为许多基于模板的容器类的类型参数使用。因为通常用于实例化模板的那些类型需要提供默认构造函数。
3) 在有虚基类的时候应该提供默认构造函数还是不提供默认构造函数。没有默认构造函数的虚基类使用起来很痛苦。这是因虚基类的构造函数所要求的参数必须由被创建对象所属的最远的派生类所提供。
条款5:小心用户自定义的转换函数
代理对象能帮助你更好地控制软件在某些方面的行为(比如隐式类型转换)。
条款6:区分自增运算符和自减运算符的前缀形式与后缀形式
后缀运算符没有使用它的参数。它的参数只是用来区分前缀与后缀函数调用。如果你没有在函数里使用函数声明时所给出的参数,许多编译器会发出警告。为了避免这些警告,经常使用的一种策略是省略掉你不打算使用的参数的名称。
条款7:不要重载“&&”、“||”和“,”
条款8:理解new和delete在不同情形下的含义
new操作符所完成的功能分成两部分。首先,分配足够的内存以便容纳所请求类型的对象。其次,它会调用构造函数初始化刚刚所分配的内存中的对象。
new operator函数调用一个函数来完成必需的内存分配,你可以重写或重载这个函数来改变它的行为。new操作符为分配内存所调用函数的名字是operator new。就像malloc一样,operator new的唯一职责是分配内存,它对构造函数一无所知。operator new所了解的只是内存分配。把operator new函数返回的未经处理的指针转换成一个对象是new操作符的工作。
有时候有些内存已经被分配但是尚未初始化,你需要在这些内存中构造一个对象。可以使用operator new函数的一个特殊版本,placement new来做这件事情。
如果你想在堆上建立一个对象,那就使用new操作符。它既分配内存又为对象调用构造函数。如果你仅仅想分配内存,那就调用operator new函数,它不会调用构造函数。如果你想定制在堆对象被建立时的内存分配过程,你应该写一个自己的operator new函数,然后使用new操作符,new操作符会调用你定制的operator new函数。如果你想在一块已经有指针指向的内存里建立一个对象,那就用placement new。
函数operator delete和delete操作符的关系与operator new和new操作符的关系一样。如果使用placement new函数在内存中创建对象,你应该避免针对这块内存使用delete操作符。因为delete操作符调用operator delete函数来释放内存,但是包含对象的内存最初不是由operator new函数分配的,placement new只是返回传递给它的指针。你应该显式调用对象的析构函数来销毁构造函数所建立的对象。