您的位置:首页 > 编程语言 > C语言/C++

Effective C++ 读书笔记(一)让自己习惯C++

2013-08-05 15:09 691 查看

1 让自己习惯C++

条款01: 视C++为一个语言联邦

View C++ as a federation oflanguages

– C。说到底C++仍是以C为基础。区块(blocks)、语句(statements)、预处理器(preprocessor)、内置数据类型(built-in data types)、数组(arrays)、指针(pointers)等统统来自C。局限:non-templates non-exceptions
non-overloading

– Object-Oriented C++。Classes(包括构造函数和析构函数),封装(encapsulation)、继承(inheritace)、多态(polymorphism)、virtual函数(晚捆绑)……等等。

– Template C++。泛型编程部分。

– STL。



C++ 高效编程守则视状况而变化,取决于你使用C++的哪一部分。

条款02: 尽量以const,enum,inline替换#define

Prefer consts,enums,and inlines to #define

– 以编译器替换预处理器。即尽量少用预处理

– #define 可能并不进入符号表(symbol table)。

Const:

• 常量指针(constant pointers)

– 例:不变的char* -based 字符串(最好使用string)

Const char* const authorName =“Scott Meyers”;



• Class专属常量

– 为了确保此常量至多只有一份实体,必须让它成为一个static成员:

ClassGamePlayer {
Private:
   static const int NumTurns = 5 ;   //常量声明
};


– 注意:只要不取它的地址,你可以声明并使用它们而无需提供定义。

– 如果你取某个class专属常量的地址或者编译器报错,你就必须提供定义。

如:const intGamePlayer::NumTurns;

由于class常量已在声明时获得初值(static),因此定义时不用再设初值。如果编译器还不允许这样,可以使用在声明外面定义赋予初值。如:const int GamePlayer::NumTurns = 5;如果还是报错,可以选择用 enum 关键字。

如:enum{ NumTurns =5};…

• Template Inline代替宏

#define CALL_WITH_MAX(a,b)    f((a) > (b)) ? (a) :(b))
int a = 5,b = 0
CALL_WITH_MAX(++a,b);   //a被累加两次
CALL_WITH_MAX(++a,b+10);//a被累加一次


template<typename T>
inline void callWithMax(cosnt T &a, cosnt T &b)
{
  f(a > b ? a : b);
}


enum

1 比较像#define而不像const。取一个enum的地址不合法,所以可以防止pointer或reference指向你的某个整数常量。

2 模板元编程的基础技术





对于单纯常量,最好以const对象或enums替换#defines;



对于形似函数的宏,最好改用inline函数替换#defines。

条款03: 尽可能使用const

Use const whenever possible

– 如果关键字const出现在星号左边,表示被指类型是常量;如果出现在星号右边,表示指针自身是常量;如果在星号两边,表示被指类型和指针两者都是常量

– Const最具有代表性的是函数声明时的应用。Const可以和函数返回值、各参数、函数自身产生关联。

– 令函数返回一个常量值,往往可以降低因客户错误而造成的意外,而不至于放弃安全性和高效性。

If(a * b = c)

– Const 成员函数

• 1)它们使class接口比较容易理解。

• 2)它们使“操作const对象”成为可能。

– 如果函数的返回类型是个内置类型,那么改掉函数返回值就不可能合法。

– Bitwise constness(physical constness)

• 成员函数只有在不更改对象的任何成员变量(static除外)时才可以说是const。也就是说它不更改对象内任何一个位(bit)。

– Logical constness

• 一个const成员函数可以修改它所处理的对象内某些bits,但只有在客户端侦测不出的情况下才可以。

– Mutable(可变的)关键字可以释放掉non-static成员变量的bitwise constness约束;

– 在const和non-const成员函数中避免重复

Const成员函数调用non-const成员函数是一种错误行为,因为对象有可能因此被改动。

– Const_cast

• 用法:const_cast<type_id>(expression)

– 该运算符用来修改类型的const或volatile属性。

– 常量指针被转化成非常量指针,并且仍然指向原来的对象;

– 常量引用被转换成非常量引用,并且仍然指向原来的对象;

– 常量对象被转换成非常量对象;

– Static_cast

• 用法:static_cast<type_id>(expression)

• 该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。





将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体;



编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量性”(conceptual constness);



当cosnt和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。

条款04: 确定对象被使用前已被初始化

Make sure that objects are initialized beforethey’re used

– 读取未初始化的值会导致不明确的行为。

l 对象的初始化何时一定发生,何时不一定发生。

– 对于无任何成员的内置类型,必须手工完成此事

– 对于内置类型以外的任何其他东西,初始化责任落在构造函数(constructors)身上。确保每一个构造函数都将对象的每一个成员初始化。

– C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。

– 初始化列表免于先调用 default构造函数然后再调用赋值操作符,只需调用一次拷贝构造函数。更高效。

– 构造函数的最佳写法是,使用 member initialization list(成员初始化表)如:

ABEntry::ABEntry(char&name,char& address,list &phones)
 :theName(name),theAddress(address),thePhones(phones)
{
…….
}


• 编译器会为用户自定义类型(user-definedtypes)之成员变量自动调用default构造函数--- 如果那些成员变量在“成员初始化列表”中没有被指定初值的话。

• 成员变量是 const 或references,它们就一定需要初值,不能被赋值。

• C++有着十分固定的“成员初始化次序”。Base classes 更早于其derived classes 被初始化,而class的成员变量总是以其声明次序被初始化。

• Static 对象,其有效时间从被构造出来直到程序结束为止,因此stack和heap-based对象被排除。

C++对于“定义于不同的编译单元内的non-localstatic对象”的初始化相对次序并无明确定义

• 小方法:将每一个non-localstatic对象放到自己的专属函数内(该对象在此函数内被声明为static),这些函数返回一个reference指向它所含的对象。


• 为内置对象进行手工初始化,因为C++不保证初始化它们;

• 构造函数最好使用成员初始化列表,而不要在构造函数本体内使用赋值操作。初始化列表列出的成员变量,其排列次序应该和它们在类中的声明次序相同;

• 为免除“跨编译单元之初始化次序”问题,请以local static对象替换non-local static对象。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: