###《More Effective C++》- 基础议题
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
};
在定义数组时,无法产生一个类型数组
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 );
它们不适用于许多
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
就不要求默认构造函数。
virtual base classes
时存在问题可能要求所有派生类都要提供
virtual base class
的constructors
自变量。
4.3. 提供默认构造函数存在的问题
- 其它成员需要检查ID是否存在,使其它
member function
变得复杂。 - 影响
class
的效率。
###《More Effective C++》- 基础议题的更多相关文章
- More Effective C++ 基础议题(条款1-4)总结
More Effective C++ 基础议题(条款1-4)总结 条款1:仔细区别pointers和references 如果有一个变量,其目的是用来指向(代表)另一个对象,但是也有可能它不指向(代表 ...
- More Effective C++ - 章节一 : 基础议题
1. 仔细区分 pointers 和 references references和pointers的差别描述如下: pointer:当需要考虑"不指向任何对象"时,或者是考虑&qu ...
- More Effective C++: 01基础议题
01:仔细区别 pointers 和 references 1:没有所谓的null reference,但是可以将 pointer 设为null.由于 reference 一定得代表某个对象,C++ ...
- MoreEffectiveC++Item35(基础议题)(条款1-4)
条款1:区别指针和引用 条款2:最好使用C++转换操作符 条款3: 绝对不要以多态的方式处理数组 条款4: 避免无用的缺省构造函数 条款1:区别指针和引用 1.指针(pointer) 使用[*/-&g ...
- C/C++ 随笔目录
[1]基础部分 (1)宏定义 <assert> <offset宏> <#pragma once> <宏定义学习> <预处理语句> <# ...
- C++学习书籍推荐《More Effective C++》下载
百度云及其他网盘下载地址:点我 编辑推荐 <More Effective C++:35个改善编程与设计的有效方法(中文版)>:传世经典书丛 媒体推荐 <Effective c++&g ...
- More Effective C++ 35 条款
一.基础议题(basics) 条款1:仔细区别 pointers 和 references(Distinguish between pointers and references) 一个基本的语法问题 ...
- More Effective C++笔记(一)(精心整理)
一.基础议题 条款1:仔细区别pointers和references 指针使用*和->,引用使用"." 引用必须指向一个已初始化的对象,不能为null,而指针可以指向某个对象 ...
- 《More Effective C++》读书笔记(零)Basic 基础条款
这是篇读书笔记,只记录自己的理解和总结,一般情况不对其举例子具体说明,因为那正是书本身做的事情,我的笔记作为梳理和复习之用,划重点.我推荐学C++的人都好好读一遍Effective C++ 系列,真是 ...
随机推荐
- 秀一套每秒处理1500+个事务的profile
秀一套每秒处理1500+个事务的profile,真实生产环境
- spring3.2.2+mybatis3.2.3+c3p0项目整合
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- [C语言(VC)] 打造自己的键盘记录器 (zaroty)
说起键盘记录,想必很多朋友都用过网上流传的一些键盘记录软件吧,但是有没有想过自己写一个呢?也许你会想:会不会很复杂啊?我可以很负责的告诉你,写键盘记录是很简单的.你所需要的仅仅是懂得一些C语言的DLL ...
- Android手机监控软件设计实现
一.需求分析: 随着IT信息技术的飞速发展,手机的普及,伴随着智能手机的出现及快速的更新换代,手机已不仅仅是一个通信工具,更是一个多功能的应用平台. 手机监控软件则是基于电脑监控软件的原理,植入手机平 ...
- [012]泛型--lambda表达式捕获
lambda表达式的捕获跟参数差不多,可以是值或者引用. 1.值捕获 与传值参数类似,采用值捕获的前期是变量可以拷贝:与参数不通透的是:被捕获的变量的值是在lambda创建时拷贝,而不是调用时拷贝. ...
- 插件就是生产力——那些不能错过的XCode插件们
古人云"工欲善其事必先利其器",打造一个强大的开发环境,是立即提升自身战斗力的绝佳途径! 晾一下我的武器库,欢迎大家选用:) 全能搜索家CodePilot 2.0 -------- ...
- Android(java)学习笔记130:ProgressBar使用的
首先我们看例程如下: 1.main.xml文件如下: <?xml version="1.0" encoding="utf-8"?> <Line ...
- C++之类的析构函数
一.认识析构函数 在我的前一篇博客介绍了类的构造函数.http://www.cnblogs.com/MrListening/p/5557114.html. 这里我们来简单说说类的析构函数,它是类的一个 ...
- java基础常识
现在总结一些经常接触到的java名词 一:java技术分类 javase:java standard editor:java标准版,主要定义java经常使用的API(Application Progr ...
- APUE(3)——文件I/O
大多数情况下,我们都会利用Standard I/O Library来进行I/O操作,而这一章所讲的I/O是UNIX系统直接提供的I/O操作,且大多是Unbuffered I/O,即每一次读或写都会出现 ...