Effective C++ 导读

Effective C++ 导读

  摘选自《Effective C++》,下文中“我”均为该书作者。记录以方便日后可能的查阅。

总述

  学习程序语言根本大法是一回事;学习如何以某种语言设计并实现高效程序则是另一回事。一组明智选择并精心设计的classes, functions, templates可使程序编写容易、直观、高效、并且远离错误。本书的目的使告诉你如何有效运用C++。
  提出的忠告大致分为两类:一般性的设计策略,以及带有具体细节的特定语言特征。eg. 选择inheritance (继承) 还是templates (模板)?选择 public继承 还是 private继承?选择 private继承 还是 composition (复合)?选择 member函数 还是 non-member函数?选择 pass-by-value 还是 pass-by-reference
  即使完全知道该做什么,完全进入正轨可能还是有点棘手。什么是assignment操作符的适当返回类型 (return type)?何时该令析构函数为virtual?当operator new 无法找到足够内存时该如何行事?

术语

1. 声明式 (Declaration)

  告诉编译器某个东西的名称和类型 (type),但略去细节。

extern int x;						//对象(object)声明式
std::size_t numDigits(int number);	//函数(function)声明式
class Widget;						//类(class)声明式
template<typename T>				//模板(template)声明式
class GraphNode;

  每个函数的声明揭示其签名式(signature),也就是参数和返回类型。numDigits函数的签名是std::size_t (int)。

2. 定义式 (Definition)

  提供编译器一些声明式所遗漏的细节。

  1. 对象:编译器为此对象拨发内存的地点。
  2. function或function template:提供了代码本体
  3. class或class template:列出它们的成员
int x;									//对象的定义式

std::size_t numDigits(int number)		//函数的定义式
{
	std::size_t digitsSofar = 1;		//此函数返回其参数的数字个数
	
	while( (number /= 10) != 0)
		++digitsSofar;
	return digitSofar;
}

class Widget{							//class的定义式
public:
	Widget();
	~Widget();
	...
};

tamplate<typename T>					//template的定义式
class GraphNode{
public:
	GraphNode();
	~GraphNode();
	...
};

3. 初始化 (Initialization)

  “给予对象初值”的过程。对用户自定义类型的对象而言,初始化由构造函数执行。

3.1 default构造函数

default构造函数是一个可被调用而不带任何实参者。这样的构造函数要不没有参数,要不就是每个参数都有缺省值。

class A{
public:
	A();				//default构造函数
};

class B{
public:
	explicit B(int x = 0, bool b = true);	//default构造函数
};

class C{
public:
	explicit C(int x);		//不是default构造函数
};

  上述B和C的构造函数都被声明为explicit,这可阻止它们被用来执行隐式类型转换 (implicit type conversions),但它们仍可被用来进行显示类型转换 (explicit type conversions)

void doSomething(B bobject);		//函数,接受一个类型为B的对象

B bobj1;
doSomething(bobj1);		//OK

B bobj2(28);
doSomething(28);		//Error! doSomething应该接受B,而非int,而int至B之间没有隐式转换

doSomething(B(28));		//OK. 使用B构造函数将int显示转换(也就是转型,cast)为一个B,以此促成一个调用

  被声明为explicit的构造函数通常比其non-explicid兄弟更受欢迎。因为它们禁止编译器执行非预期(往往也不被期望)的类型转换。除非我有一个好理由允许构造函数被用于隐式类型转换,否则我会把它声明为explicit。

3.2 copy构造函数

  copy构造函数被用来“以同型对象初始化自我对象”,copy assignment操作符被用来“从另一同型对象中拷贝其值到自我对象”

class Widget{
public:
	Widget();								//default构造函数
	Widget(const Widget& rhs);				//copy构造函数
	Widget& operator=(const Widget& rhs);	//copy assignment操作符
	...
};
Widget w1;			//调用default构造函数
Widget w2(w1);		//调用copy构造函数
w1 = w2;			//调用copy assignment操作符

//看到赋值符号要小心,因为“=”语法也可以用来调用copy构造函数
Widget w3 = w2;		//调用copy构造函数

  “copy构造”和“copy赋值”:如果一个新对象被定义(w3),一定会有个构造函数被调用,不可能调用赋值操作。如果没有新对象定义(w1 = w2),就不会有构造函数被调用,那当然就是赋值操作被调用。

  copy构造函数是一个尤其重要的函数,因为它定义一个对象如何 pass by value.

bool hasAcceptableQuality(Widget w);
...
Widget aWidget;
if(hasAcceptableQuality(aWidget)) ...

  参数w以by-value方式传递给hasAcceptableQuality,所以在上述调用中aWidget被复制到w体内。这个复制动作由Widget的copy构造函数完成。Pass-by-value意味“调用copy构造函数”。以by-value传递用户自定义类型通常不大好,Pass-by-reference-to-const 往往是比较好的选择。详见条款20。

4. STL (Standard Template Library, 标准模板库)

  C++标准程序库的一部分,致力于容器(如 vector, list, set, map 等等)、迭代器(如 vector::iterator, set::iterator等等)、算法(如 for_each, find, sort 等等) 及相关机能。
  许多相关机能以函数对象 (function objects) 实现,那是“行为像函数”的对象。这样的对象来自于重载 operator() (function call 操作符)的classes

5. 不明确行为

6. 接口 (Interface)

  Java 和 .NET都提供 Interfaces 为语言元素,但C++没有。当使用术语“接口”时,一般谈的时函数的签名 (signature) 或 class 的可访问元素(例如,class的 “public 接口” 或 “protected 接口” 或 “private 接口”),或是针对某template类型参数需为有效的一个表达式(条款41)。即本书中所说的接口完全是指一般性的设计观念。

7. 客户 (Client)

  指某人或某物,他(它)使用你写的代码(通常是一些接口)。函数的客户时其使用者,也就是程序中调用函数(或取其地址)的那一部分,也可以说时编写并维护那些代码的人。Class或template的客户则是程序中使用class或template的那一部分,也可以说时编写并维护那些代码的人。说到“客户”时通常我指的是程序员,因为程序员可能被迷惑、被误导、或因糟糕的接口而愤怒,他们所写的代码却不会有这种情绪。

8. 其它

  本书中常常掩盖functions和function templates之间的区别,以及classes和class templates之间的区别。因为对其中之一为真者往往对另一方也为真。当不是这种情况的时候,作者会区分classes, functions及它们所对应的templates。
  当在程序批注中提到构造函数和析构函数时,有时会使用缩写字 ctordtor

命名习惯 (Naming Conventions)

  lhsrhs分别代表"left-hand side"(左手端)和 “right-hand side”(右手端)。常常以它们作为二元操作符 (binary operators) 函数如operator== 和 operator* 的参数名称。例:若a和b标识两个有理数对象,而若Rational对象可悲一个non-member operator* 函数执行乘法(如条款24),那么下面表达式 :
      a * b
等价于以下的函数调用:
      operator* (a, b)

  在条款24中我声明此一operator* 如下:
const Rational operator* (const Rantional& lhs, const Rational& rhs);
  如你所见,左操作数a变成函数内的lhs,右操作数b则变成rhs。

  对于成员函数,左侧实参由this指针表现出来,所以有时我单独使用参数名称rhs。

  我常将”指向一个T型对象“的指针命名为pt,意思是"pointer to T"。下面是一些例子:

Widget* pw;				//pw = "ptr to Widget"
class Airplane;
Airplane* pa;			//pa = "ptr to Airplane"
class GameCharacter;
GameCharacter* pgc;		//pgc = "ptr to GameCharacter"

  对于references我使用类似习惯:rw可能是个reference to Widget,ra则是个reference to Airplane。

  当我讨论成员函数时,偶尔会以mf为名。

关于线程 (Threading Consideration)

  线程安全性时许多程序员面对的主题。作者对 “标准C++” 和真实世界之间的这个缺口的处理方式是,如果所检验的C++构建在多线程环境中有可能引发问题,就把它指出来。这远远无法构成一本C++多线程编程专著,却能让一本C++编程书籍尽管大量限制其自身处于单线程考虑之下仍承认多线程的存在,并指出 “有线程概念的程序员” 在作者所提供的忠告时需特别谨慎的地方。

TR1 和 Boost

  本书中处处提到TR1 (条款54) 和Boost (条款55).

TR1

  TR1 (“Technical Report 1”) 十一分规范,描述加入C++标准程序库的诸多新机能。这些机能以新的class templates 和 function templates 形式体现,针对的题目有 hash tables, reference-counting smart pointers, regular expressions, 以及更多。所有TR1组件都被置于命名空间 tr1 内,后者嵌套于命名空间std内。

Boost

  Boost是个组织,亦是一个网站 (http://boost.org),提供可移植、同僚复审、源码开放的C++程序库。大多数TR1机能是以Boost工作为基础。在编译器厂商于其C++程序中含入TR1之前,对那些搜寻TR1实现品的开发人员而言,Boost网站可能是第一个逗留点。Boost提供比TR1更多的东西。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值