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

1. 仔细区分 pointers 和 references

references和pointers的差别描述如下:

pointer:当需要考虑"不指向任何对象"时,或者是考虑"在不同时间指向不同对象"的能力时,应该采用pointer。前一种情况可以将pointer设为null,后一种可以改变pointer所指对象。

reference:当确定"总是会代表某个对象",而且"一旦代表了该对象就不能再改变",那应该使用reference。 reference不能为空,因此无需做判空操作,相对pointer使用效率更高。某些操作符重载 operator[],operator= 采用reference实现。

结论: 当知道需要指向某个东西,而且绝不会改变指向其他东西,或是当实现一个操作符而其语法需求无法由pointers实现,就应选择references。 其任何时候,请采用 pointers。

2. 最好使用 C++ 转型操作符

由于旧式的c转型几乎允许任何类型转换为任何其他类型,这样是十分拙劣的,如果每次转型能够精确地指明转型意图,会更好。还有就是旧式转型难以辨识,导致查看代码时,会遗漏转型操作。C++ 引进4个新的转型操作符:

旧式 C 转型:

(type) expression

C++ 转型:

1. static_cast<type>(expression) :
基本拥有与 C 旧式转型相同的威力和意义

2. dynamic_cast<type>(expression) :
用来执行继承体系中"安全的向下转型或者跨系转型动作",我们可以利用dynamic_cast,将 "指向父类对象的指针或引用" 转型为 "指向子类对象的指针或者引用"
,并得知是否转型成功,转型失败会返回一个null指针(当转型对象时指针)或一个exception(当转型对象时reference)

3. const_cast<type>(expression) :
改变表达式常量性(constness)或者 变易性(volatileness)

4. reinterpret_cast<type>(expression) :
与编译平台相关,不具有移植性。最常用用途是转换 "函数指针" 类型,不到非用不可的地步不用,因为某些情况下会出现转型不正确。 

例如:
typedef void (*FuncPtr)();
FuncPtr funcPtrArrary[10];

int doSomething();

funcPtrArrary[0] = reinterpret_cast<FuncPtr> (&doSomething); // 将返回值为 int 的函数指针转换为返回值为void*

如果你想为一个不涉及继承机制的类型执行转型动作,可使用static_cast;要改变常量性,必须使用const_cast;涉及继承机制,使用dynamic_cast 或者 static_cast; reinterpret_cast 把一个指针转换成一个整数,也可以把一个整数转换成一个指针。

3. 绝对不要以多态的方式处理数组

大致代码如下:

// 简单继承关系
class BST{...};
class BalancedBST: public BST{...};

// 打印接口

void printfBSTArray(ostream& s, const BST arrry[], int numElements)
{
  for(int i = 0; i < numElements; ++i){
    s << array[i];
  }
}

BalancedBST bBSTArray[10];
...
printfBSTArray(cout, bBSTArray, 10); // 发生不可预期问题

上述代码中,编译器为了能够访问整个数组,编译器必须有能力决定数组对象大小,编译器认为大小为BST类大小,但是我们传入的是其子类,而子类对象大小肯定是大于父类的,因此导致这里会发生不可预期错误。

多态和指针算术不能混用。而数组对象几乎总是会涉及指针的算术运算,所以数组和多态不要混用。

4. 非必要不提供 default constructor

由不带参数的构造函数,或者为所有的形参提供默认实参的构造函数,被称为默认构造函数(default constructor)。

class foo
{
public:
  foo(); // 默认构造函数
  ...
};

在一个完美世界中,凡可以"合理的从无到有生成对象"的class,都应该内含默认构造函数,而"必须有某些外来信息才能生成对象"的class,则不必拥有默认构造函数。但是,当一个类缺乏default constructor,使用时会受到限制。

class foo
{
public:
  foo(int Id); // 构造函数
  ...
};

foo bestfoo[10]; // 错误! 无法调用构造函数
foo *best = new foo[10]; // 错误! 无法调用默认构造函数

有介绍三种办法来解决无默认构造函数的限制:

1. non-heap 数组

foo fooTest[] = {foo(1), foo(2), foo(3)}; // 构造函数获得id,可以成功

2. 指针数组。 缺点:指针数组要删除,否则内存泄漏;保存指针,浪费内存。

typedef foo* foo_ptr;

foo_ptr bestfoo[10]; // 没问题,存在的指针,不用调用构造函数

foo_ptr *best = new foo_ptr[10] // 也没问题,数组堆上存的是指针

for(int i = 0; i < 10; ++i){
  best[i] = new foo(Id number); // 传入ID 初始化对象
}

3. placement new。分配内存时可指定内存位置。

// 首先申请一块适当大小的缓存,可以是堆上的,也可以是其他特殊缓存(例如共享内存)
void *rawMemory = operator new[](10*sizeof(foo)); 

// 让 best 指针指向该块内存首地址
foo* best = static_cast<foo*>(rawMemory);

// 然后利用 placement new 构造内存中的 foo 对象
for(int i = 0; i < 10; ++i){
  new (&best[i]) foo(Id number); // (&best[i]) : 内存位置
}

缺乏 default constructor 类的第二个缺点,将不适用于许多基于模板实现的容器类。

第三个缺点,虚基类没有默认构造函数,将导致所有继承类都要注意提供虚基类构造函数自变量,十分麻烦。

缺乏默认构造虽然会导致上述三种限制,但是如果不需要默认构造函数的类却加了默认构造函数,将导致该类内部member functions逻辑变得复杂,以及影响调用该类的客户代码的效率。 因此非必要不提供 default constructor。

2018年10月1日14:59:02

原文地址:https://www.cnblogs.com/blog-yejy/p/9734683.html

时间: 2024-11-26 05:25:58

More Effective C++ - 章节一 : 基础议题的相关文章

【C++常识】more effective C++ 使用条款——基础议题/运算符

第一章:基础议题 Item M1:指针与引用的区别 1.指针可以不初始化,引用必须初始化 2.指针可以为空指针,引用不可以为空 3.指针可以改变指向,引用初始化后就不能改变指向的对象 4.指针占用4个字节,引用只是别名,理论上是不占用空间的,但是这个别名本身是要占用空间的,因此也可以说引用时占用空间的 5.引用比指针效率高,因为引用直接操作的是原对象本身 Item M2:尽量使用C++风格的类型转换 1.C++风格的四种转换:static_cast ,const_cast,dynamic_cas

《More Effective C++》重点摘要一:基础议题

仔细区别pointers和references.指针和引用有些相似,他们本身都是对存在于某个地方的对象(不是指class)的指示,但是他们有着本质的区别.指针变量存储所指对象的地址,所指的对象可以是null,只要可以寻址就行.而引用是某个已经存在对象的别名,所以不可以先声明一个引用,经过一段时间(代码)后让它指向某个对象. 最好使用C++转型操作符.C++提供了自己的四种转型操作符: 1) static_cast.拥有与C旧式转型相同的意义与限制,但不能移除表达式的常量性,因为有const_ca

第五章节 Servlet基础

目录 一.Web站点的建立  二.创建 Servlet的三种方法 一.Web站点的建立  当客户端提交请求的时候,由tomcat容器之类的Web容载入并运行,然后将生成的动态页面返回给客户端. 如何能让Web容器找到编写好的Servlet文件呢,这就需要建立一个Web站点,并对站点进行配置. Tomcat中有一个webapps文件,相当于默认站点,可以在这个文件中通过 下面的步骤来创建一个Web站点. 1.定义站点名. 2.创建WEB-INFO文件,这个文件用来存放Web站点的配置文件,自己编写

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

百度云及其他网盘下载地址:点我 编辑推荐 <More Effective C++:35个改善编程与设计的有效方法(中文版)>:传世经典书丛 媒体推荐 <Effective c++>(Scott Meyers第一本书)的荣耀:"对于任何渴望在中阶或高阶层面精通c++的人,我慎重推荐<Effective c++>," --(The C/C++User's Journal) 作者简介 作者:(美国)梅耶(Scott Meyers) 译者:侯捷 Scott

数据库基础再总结

再次导读书本第一章节对整本书的基础概述: 数据库(Database,DB):是存放数据的仓库.是长期储存在计算机内.有组织的,可共享的数据集合. 数据库中的数据可分为两类: 1)用户数据:一般由用户定义和使用 2)系统数据:数据库系统定义和使用的数据,称为数据字典(DD,Data Dictionary) 数据库管理系统(Database Managemetn System,DBMS):是位于用户和操作系统之间的一层数据管理软件: 主要功能:1)数据定义:DDL 2)数据操纵(或存取):DML 3

《More Effective C++》读书笔记

http://www.cnblogs.com/tianyajuanke/archive/2012/11/29/2795131.html 一.基础议题(Basics) 1.仔细区别 pointers 和 references 当一定会指向某个对象,且不会改变指向时,就应该选择 references,其它任何时候,应该选择 pointers. 实现某一些操作符的时候,操作符由于语义要求使得指针不可行,这时就使用引用. 二者之间的区别是:在任何情况下都不能用指向空值的引用,而指针则可以:指针可以被重新

C#基础--之数据类型【转】

在第一章我们了解了C#的输入.输出语句后,我这一节主要是介绍C#的基础知识,本节的内容也是后续章节的基础,好的开端等于成功的一半.在你阅读完本章后,你就有足够的C#知识编写简单的程序了.但还不能使用继承或其它面向对象的特征.  本章主要针对以下几个部份来进行讲解:    1.电脑是由什么来存储所使用的数据?    2.基本数据类型有哪些?    3.如何声明变量和赋值?    4.变量和常量的区别?    5.不同数据类型之间是如何转换的? 下面,我们现一个一个的来了解这些问题.  一.电脑是由

2018最新SpringBoot2.0教程(零基础入门)

一.零基础快速入门SpringBoot2.0 1.SpringBoot2.x课程全套介绍和高手系列知识点 简介:介绍SpringBoot2.x课程大纲章节 java基础,jdk环境,maven基础 2.SpringBoot2.x依赖环境和版本新特性说明 简介:讲解新版本依赖环境和springboot2新特性概述 3.快速创建SpringBoot2.x应用之手工创建web应用 简介:使用Maven手工创建SpringBoot2.x应用 4.快速创建SpringBoot2.x应用之工具类自动创建we

从基础到实战 手把手带你掌握新版Webpack4.0

原文配套视频资源获取链接:点击获取 原文配套源码资源获取链接:点击获取 第1章 课程导学(打消你的学习疑虑) 掌握Webpack越来越成为前端工程师的标配技能,本章会对课程整体进行介绍,打消你的学习疑虑. 1-1 课程导学试看 第2章 Webpack 初探 本章通过清晰易懂的例子,带你了解 Webpack 的产生背景,以及其能够解决的问题.在此基础上,完成开发环境的搭建,Webpack 的安装,并进行最基础的 Webpack 使用讲解. 2-1 webpack 究竟是什么? 2-2 什么是模块打