01:仔细区别 pointers 和 references

1:没有所谓的null reference,但是可以将 pointer 设为null。由于 reference 一定得代表某个对象,C++ 因此要求 references 必须有初值,但是pointers 就没有这样的限制。

没有所谓的 null reference 这个事实意味使用 references 可能会比使用 pointers更富效率。这是因为使用 reference 之前不需测试其有效性。

2:Pointers 和 references 之间的另一个重要差异就是,pointers 可以被重新设值,指向另一个物件,reference 却总是指向它最初获得的那个物件。

02:最好使用C++转型操作符

1:低阶转型动作,像goto一样地被视为程序设计上的贱民。尽管如此,某些情况下,转型可能是必要的。

2:旧式的C转型方式,几乎允许你将任何型别转换为任何其他型别,这是十分拙劣的。更好的方式是每次转型都能够更精确地指明意图。旧式转型的第二个问题是它们难以辨识,旧式转型的语法形式是 (type) expression 这样的,不只是人眼难以辨识,诸如 grep 之类的工具也无法区分语法上极类似的一些非转型写法。

3:为解决C旧式转型的缺点,C++ 导入四个新的转型运算符:static_cast, const_cast, dynamic_cast 和 reinterpret_cast。

static_cast基本上拥有与C旧式转型相同的威力与意义,以及相同的限制。例如你不能够利用 static_cast 将一个 struct 转型为 int 或将一个double转型为pointer;

const_cast最常见的用途就是将某个对象的常数性去除掉;

dynamic_cast用来执行继承体系中“安全的向下转型或跨系转型动作”。也就是说你可以利用 dynamic_cast,将“指向  base class objects之pointers或references”转型为“指向 derived(或 sibling base)class objects之 pointers 或 references”,并得知转型是否成功。如果转型失败,会以一个null指针(当转型对象是指针)或一个exception(当转型对象是  reference)表现出来。

最后一个转型运算符是reinterpret_cast。这个运算符的转换结果几乎总是与编译平台息息相关。所以 reinterpret_casts 不具移植性。最常见的用途是转换“函数指针”。假设有一个函数指针数组:

typedef void (*FuncPtr)();
FuncPtr funcPtrArray[10];

现在希望将以下函数指针放进 funcPtrArray 中:

int doSomething();

使用 reinterpret_cast,可以强迫编译器编译通过:

funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething);

函数指针的转型动作,并不具移植性,某些情况下这样的转型可能会导至不正确的结果,所以应该尽量避免将函数指针转型。

03:绝对不要以多态方式处理数组

假设有下面的代码:

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];}
}BalancedBST bBSTArray[10];
printBSTArray(cout, bBSTArray, 10);

上面的代码编译器不会报错,但是针对array[i],它的本质是*(array+i),编译器在编译期间必须知道数组中的对象大小。函数原型中,参数array声明为类型为BST的数组,所以编译器认为数组中的每个元素必然都是BST对象,然而实际上数组元素都是BalancedBST对象,这就有问题了。

上述问题有时候会以一种更隐秘的方式出现:

void deleteArray(ostream& logStream, BST array[])
{delete [] array;
}
BalancedBST *balTreeArray = new BalancedBST[50];
deleteArray(cout, balTreeArray);

delete数组时,数组中每一个元素的析构函数就会被调用,所以,delete []array这样的语句,会产生下面的代码:

for (int i = the number of elements in the array - 1; i >= 0; --i)
{array[i].BST::~BST();
}

错误的原因与上面是一样的。

04:非必要不提供default constructor

1:有许多对象,如果没有外来信息,就没有办法执行一个完全的初始化动作。例如一个用来表现联络簿字段的 class,如果没有获得外界指定的人名,产生出来的对象将毫无意义。

凡可以“合理地从无到有产出对象”的 classes,都应该内含 default constructors,而“必须有某些外来信息才能产出对象”的 classes,则不必拥有default constructors。

2:假定有一个NoDefault类,它没有定义自己的默认构造函数,却有一个接受一个string实参的构造函数。NoDefault没有默认构造函数,意味着它具有以下限制:

a:具有NoDefault成员的每个类的每个构造函数,必须通过传递一个初始的string值给NoDefault构造函数来显式地初始化 NoDefault成员。

b:编译器将不会为具有NoDefault类型成员的类合成默认构造函数。如果这样的类希望提供默认构造函数,就必须显式地定义,并且默认构造函数必须显式地初始化其NoDefault成员。

c:NoDefault类型不能用作动态分配数组的元素类型。

d:NoDefault类型的静态分配数组必须为每个元素提供一个显式的初始化式。

e:如果有一个保存NoDefault对象的容器,例如vector,就不能使用接受容器大小而没有同时提供一个元素初始化式的构造函数。

f:如果NoDefault作为virtual base classe,则要求其最底层的派生类--不管距离多么遥远--都必须知道其意义,从而提供NoDefault的构建自变量。

3:对于有些类而言,盲目定义default constructors返回会带来不好的影响。假设在某些公司,所有仪器设备都必须贴上一个识别号码;为这种用途而设计的类EquipmentPiece,如果其中没有供应适当的ID号码,将毫无意义,因此不应该定义默认构造函数。然而如果为其定义了:

class EquipmentPiece {
public:EquipmentPiece(int IDNumber = UNSPECIFIED);
...
private:static const int UNSPECIFIED;//  一个魔术数字,// 意味没有被指定 ID  值
};

这种代码,肯定会使得该类内其他的成员函数变得复杂:因为允许一个无ID的EquipmentPiece对象能够存在,其他成员函数必须检查ID是否存在,这就造成了时间和空间上的代价。如果构造函数保证所有字段能正确的初始化,就不会出现这种问题。因此,这样的类就不应该有默认构造函数。

转载于:https://www.cnblogs.com/gqtcgq/p/9464357.html

More Effective C++: 01基础议题相关推荐

  1. java 01 02_Java知识系统回顾整理01基础02面向对象01类和对象

    一.面向对象实例--设计英雄这个类 LOL有很多英雄,比如盲僧,团战可以输,提莫必须死,盖伦,琴女 所有这些英雄,都有一些共同的状态 比如,他们都有名字,hp,护甲,移动速度等等 这样我们就可以设计一 ...

  2. Jmeter 入门 从0-1 基础篇-实操

    Jmeter 入门 从0-1 基础篇 笔记有的图片链接可能失效了,等我修改好了在来编辑哈 文章目录 1 JMeter 1.1 JMeter环境搭建和基本使用 1.1.1 JMeter环境搭建 1.1. ...

  3. 基因表达分析-01基础概念

    基因表达分析-01基础概念 一. 检测方法 Q-PCR 基因芯片(Microarray)‌高通量 表达序列标签(EST) 基因表达系列载体(SAGE) 转录组测序(RNA-seq)‌高通量 二. 基因 ...

  4. Bootstrap响应式Web开发笔记01——基础入门

    Bootstrap响应式Web开发笔记01--基础入门 Bootstrap响应式Web开发笔记02--移动端页面布局 Bootstrap响应式Web开发笔记03--Bootstrap栅格系统 Boot ...

  5. PLC编程入门-01基础知识介绍

    PLC编程入门-01基础知识介绍 PLC的组成结构 PLC编程语言: PLC输入输出的特点 输入 输出 PLC的组成结构 简图 明细图 CPU:控制器和运算器本身就是CPU主要组成部分,和PC的CPU ...

  6. 图神经网络学习笔记-01基础

    图神经网络-01基础-图与图学习 文章目录 图神经网络-01基础-图与图学习 图是什么 图的定义 图的基本表示方法 e.g 图的存储 图的类型和性质 图算法 1. 寻路和图搜索算法 1). 搜索算法 ...

  7. Python 基础学习 00 01 基础语法规则

    00 01 基础语法规则 前言 此专栏笔记是个人学习 Python 过程中的个人笔记,记录方式主要以个人习惯为主,记录内容会包括个人学习 Python 中的知识点,以及使用过程中的遇到的问题记录.如果 ...

  8. arduino 学习笔记及课件01基础入门

    arduino 学习笔记及课件01基础入门 以下学习笔记中图片部分由太极创客视频截图所得 概论 一. 引脚及信号 1.1引脚模式 INPUT:当Arduino没有使用上拉电阻或下拉电阻而直接与开放的开 ...

  9. PHP学习笔记01——基础语法

    1 <!DOCTYPE html> 2 <html> 3 <?php 4 // 1.使用$加变量名来表示变量,php是弱类型语言,不要求在使用变量前声明,第一次赋值时变量 ...

最新文章

  1. hive插入表的insert 执行计划_0651-6.2.0-启用Sentry后Impala执行SQL失败问题分析
  2. number to string - LeetCode【数字 = 字符串】
  3. 外贸常用术语_外贸干货!做外贸常用的贸易术语,几个妙招教你快速记住!
  4. 制作Scary爬虫步骤
  5. 通俗讲清楚为什么使用信息熵增益比而不是信息熵增益?
  6. 【算法分析与设计】埃氏筛素数算法
  7. 【ASK】设置网卡启动遇到的事!
  8. Python中fastapi构建的web项目配置环境变量
  9. WIN10专业版64位21H2正式版19044.1826
  10. 知乎企业认证怎么弄?知乎企业号怎么申请?详解来了
  11. 制作可启动DOS优盘
  12. 华为手机为什么打不开微信连接到服务器,华为手机微信打不开如何解决? 华为手机微信打不开解决方法介绍!...
  13. 【烈日炎炎战后端】Git(0.1万字)
  14. mysql workbench 建模教程_MySQL Workbench 使用教程 (三)
  15. 工作中的高效工具推荐,职场人士必备便签小工具
  16. ajax get传递数组参数吗,ajax 传递数组参数
  17. Arduino uno esp01s 硬串口通信
  18. 关于图灵测试和中文屋Chinese room的理解
  19. 喜大普奔——Mapbox GL JS支持多种投影了
  20. TOM怎么注册字母邮箱,字母邮箱注册方法

热门文章

  1. uploadify 上传文件并带有随机数文件名生成
  2. servlet 变量 及servlet 初始化 和销毁 ThreadLocal
  3. UniCode 下 CString 转 char* 的方法
  4. Moses 里的参数(未完成)
  5. 浅谈公司形象网站的设计流程
  6. 对Android GPS获取位置信息的新研究.
  7. 关于 TStringList.Assign - 回复 u9cm 的问题
  8. Nagios借助yahoo.cn邮箱实现手机短信报警功能
  9. vivado使用自带IP核和创建自己定义的IP核
  10. jittor和pytorch生成网络对比之cgan