More Effective C++

#@author:       gr
#@date: 2015-05-11
#@email: forgerui@gmail.com

一、仔细区别pointers和references

1.1. 初始化

指针可以不初始化,引用必须初始化为。

引用没有null reference,指针可以设为NULL.

//指针初始化为0,NULL,nullptr
char *str = 0;
int a = 1;
//引用必须初始化,int &b;是错误的
int &b = a;

1.2. 效率

因为不存在null reference,引用使用前不需要测试其有效性,效率比指针高一些。

void print(const double& rd)
{
cout << rd; //不需要测试有效性
}
void print(const double* rd)
{
if (*rd)
cout << rd; //需要测试是否为空
}

1.3. 指向

指针可以改变指向的对象,而reference始终指向最终指向的对象。

string s1("aaa");
string s2("bbb");
string& rs = s1;
string *ps = &s2;
rs = s2; //不变,仍指向s1,但s1值改变了
ps = &s1; //改变,改为指向s1

在不同时间指向不同对象,使用指针;一旦代表了该对象就不能够改变,这时使用reference。比如operator[]操作符,应该使用引用;如果返回指针在赋值时需要写成下面的样子,很不直观,容易产生误解:

vector<int> a(10);
a[5] = 2; //使用引用
*a[5] = 2; //使用指针

二、最好使用C++转型操作符

2.1. 新式转型

static_cast<type>(expression)		//最常用的转型
const_cast<type>(expression) //将常量性去掉
dynamic_cast<type>(expression) //继承转换,将父类转为子类,无法转换,返回null或摄氏
reinterpret_cast<type>(expression) //与编译平台有关,不具移植性

2.2. reinterpret_cast

typedef void (*FuncPtr)();
FuncPtr funcPtrArray[10];
int doSomething(); //将doSomething放funcPtrArray中
funcPtrArray[0] = &doSomething; //错误,类型不符,无法存放
funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething);

2.3. 先用旧式取代新式,方便升级

#define static_cast(TYPE, EXPRESSION) ((TYPE) (EXPRESSION))
#define const_cast(TYPE, EXPRESSION) ((TYPE) (EXPRESSION))

虽然,新式转型又长又臭,但使用新式转型更加清晰,也会让你尽量减少转型的使用。

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

3.1. 多态数组存在的问题

class BST{...};
class BalancedBST : public BST{...}; void printBSTArray(ostream& s, const BST array[], int numElements)
{
for (int i = 0; i < numElements; ++i)
{
s << array[i];
}
} BST BSTArray[10];
printBSTArray(cout, BSTArray, 10); //表现良好 BalancedBST bBSTArray[10];
printBSTArray(cout, bBSTArray, 10); //传入子类,存在问题

如果想对子类的数组进行多态处理,往往因为子类的大小被解析成父类的大小,而无法达到想要的结果。这样会产生不可预测的结果。

同样在进行数组删除时,同样也会遇到这样的问题,所以数组和多态不要一起使用

牢记条款33所说“具体类不要继承自另一个具体类”可以避免这个错误。

四、非必要不提供default constructors

4.1. 无中生有

有些类可以“无中生有”产生,然而有些类无法“无中生有”,因为这种产生的对象毫无意义。如:一个通信簿字段的class,如果没有获得外界指定的人名,产生出来的对象将毫无意义。这些对象不应该提供default constructor

4.2. 缺乏default constructor带来的问题

如下面的EquipmentPiece,它没有默认的构造函数,它将产生一些问题。

class EquipmentPiece{
public:
EquipmentPiece(int IDNumber); //因为定义了其它ctors,所以编译器不会再生成defalut ctors
};
  1. 在定义数组时,无法产生一个类型数组

     EquipmentPiece bestPiece[10];			//错误,无法调用EquipmentPiece ctors
    EquipmentPiece *bestPieces = new EquipmentPiece[10]; //错误

    解决这个问题方法是使用“指针数组”而非“对象数组”:

     typedef EquipmentPiece* PEP;
    PEP bestPiece[10]; //很好,定义10个元素的指针数组
    PEP *bestPieces = new PEP[10]; //也很好
    for (int i = 0; i < 10; ++i)
    bestPieces[i] = new EquipmentPiece( ID Number );
  2. 它们不适用于许多template-based container classes,这些contrainer希望实例化的目标得有一个default constructors

     template <typename T>
    class Array{
    public:
    Array (int size);
    private:
    T *data;
    };
    template <typename T>
    Array<T>::Array(int size)
    {
    data = new T[size]; //会报错,需要调用default ctors
    }

解决方法是谨慎设计template,消除对default ctors的需求。比如vector就不要求默认构造函数。

  1. virtual base classes时存在问题

    可能要求所有派生类都要提供virtual base classconstructors自变量。

4.3. 提供默认构造函数存在的问题

  1. 其它成员需要检查ID是否存在,使其它member function变得复杂。
  2. 影响class的效率。

###《More Effective C++》- 基础议题的更多相关文章

  1. More Effective C++ 基础议题(条款1-4)总结

    More Effective C++ 基础议题(条款1-4)总结 条款1:仔细区别pointers和references 如果有一个变量,其目的是用来指向(代表)另一个对象,但是也有可能它不指向(代表 ...

  2. More Effective C++ - 章节一 : 基础议题

    1. 仔细区分 pointers 和 references references和pointers的差别描述如下: pointer:当需要考虑"不指向任何对象"时,或者是考虑&qu ...

  3. More Effective C++: 01基础议题

    01:仔细区别 pointers 和 references 1:没有所谓的null reference,但是可以将 pointer 设为null.由于 reference 一定得代表某个对象,C++ ...

  4. MoreEffectiveC++Item35(基础议题)(条款1-4)

    条款1:区别指针和引用 条款2:最好使用C++转换操作符 条款3: 绝对不要以多态的方式处理数组 条款4: 避免无用的缺省构造函数 条款1:区别指针和引用 1.指针(pointer) 使用[*/-&g ...

  5. C/C++ 随笔目录

    [1]基础部分 (1)宏定义 <assert> <offset宏> <#pragma once> <宏定义学习> <预处理语句> <# ...

  6. C++学习书籍推荐《More Effective C++》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <More Effective C++:35个改善编程与设计的有效方法(中文版)>:传世经典书丛 媒体推荐 <Effective c++&g ...

  7. More Effective C++ 35 条款

    一.基础议题(basics) 条款1:仔细区别 pointers 和 references(Distinguish between pointers and references) 一个基本的语法问题 ...

  8. More Effective C++笔记(一)(精心整理)

    一.基础议题 条款1:仔细区别pointers和references 指针使用*和->,引用使用"." 引用必须指向一个已初始化的对象,不能为null,而指针可以指向某个对象 ...

  9. 《More Effective C++》读书笔记(零)Basic 基础条款

    这是篇读书笔记,只记录自己的理解和总结,一般情况不对其举例子具体说明,因为那正是书本身做的事情,我的笔记作为梳理和复习之用,划重点.我推荐学C++的人都好好读一遍Effective C++ 系列,真是 ...

随机推荐

  1. hdoj 4325 Flowers【线段树+离散化】

    Flowers Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  2. BNUOJ 26579 Andrew the Ant

    LINK:Andrew the Ant 题意:给一根长度为L的木头,上面有A只蚂蚁[每只蚂蚁给出了初始行走的方向,向左或向右].当两只蚂蚁相碰时,两只蚂蚁就朝相反的方向行走~╮(╯▽╰)╭问的是:最后 ...

  3. SQL Server Profiler参数说明

    上图依次说明为: TextDate 依赖于跟踪中捕获的事件类的文本值: ApplicationName 创建 SQL Server 连接的客户端应用程序的名称.此列由该应用程序传递的值填充,而不是由所 ...

  4. 【Stage3D学习笔记续】山寨Starling(四):渲染代码实现及测试程序

    本章会实现最核心的代码,所以涉及点会比较多,这里会发布一个版本,方便日后的回退查看. 点击下载:https://codeload.github.com/hammerc/hammerc-study-St ...

  5. Java编程 -- 命名规范

    转自:http://www.hawstein.com/posts/google-java-style.html#Naming 命名约定 5.1 对所有标识符都通用的规则 标识符只能使用ASCII字母和 ...

  6. iOS开发-网络-合理封装请求接口

    概述 如今大多App都会与网络打交道,作为开发者,合理的对网络后台请求接口进行封装十分重要.本文要介绍的就是一种常见的采用回调函数(方法)的网络接口封装,也算的是一种构架吧. 这个构架主要的idea是 ...

  7. 终端神器 iterm

    1.简介 mac自带的终端terminal算蛮好用的, 但相比另一款优秀的终端软件iterm,iterm这款神器不逊于mac自带的终端.它支持了很多快捷键, 深受键盘党的喜爱. 2.下载 http:/ ...

  8. ThinkPHP Volist标签

    Volist标签主要用于在模板中循环输出数据集或者多维数组. volist标签(循环输出数据) 闭合 非闭合标签 属性 name(必须):要输出的数据模板变量 id(必须):循环变量 offset(可 ...

  9. TigerDLNA for ios 集成Tlplayer

    好久没有写博客了,这次带着TigerDLNA for ios 跟大家见面 什么都不说先上图 1.优点 优点由于libTigerDLNA使用uiview封装,所以大家可以很方便的集成到自己的项目中.由于 ...

  10. sessionID和cookie

    一.cookie机制和session机制的区别***************************************************************************** ...