《Effective C++》读书笔记II

让自己习惯C++

条款01:视C++为一个语言联邦(View C++ as a federation of languages)

C++是个多重范型编程语言(multiparadigm programming language),一个同时支持过程形式、面向对象形式、函数形式、泛型形式、元编程形式的语言。C++相关的次语言主要包括四个:CObject-Oriented C++Template C++STL

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

 

条款02:尽量以constenuminline替换#defineprefer constsenumsand inlines to #defines.

1)class专属常量,通常为了确保class专属常量至多只有一份实体,你必须让它成为一个static成员。class专属常量通常需要一个放进实现文件的定义式。

2)enum hack的行为某个方面说比较像#define而不像const,例如取一个const的地址是合法的,而取一个enum的地址是不合法,而取一个#define的地址通常也不合法。

3)对于单纯常量,最好以const对象或enums替换#define

4)对于形式函数的宏,最好改用inline函数替换#defines

 

条款03:尽可能使用constUse const whenever possible

关键字const多才多艺,可以用它在classes外部修饰globalnamespace作用域中的常量,或修饰文件、函数、或区块作用域中被声明为static的对象,也可以用它来修饰classes内部的staticnon-static成员变量。面对指针,也可以指出指针自身、指针所指物,或两者都(或都不)是const

1)const成员函数,将const实施于成员函数的目的,是为了确认该成员函数可作用于const对象身上。

2)两个成员函数如果只是常量性(constness)不同,可以被重载。

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

4)bitwise const(又称physical constness):成员函数只有在不更改对象之任何成员变量(static除外)时才可以说是const,也就是说它不更改对象内的任何一个bit

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

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

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

 

条款04:确定对象被使用前已先被初始化(Make sure that objects are initialized before they’re used.

1)为内置型对象进行手工初始化,因为C++不保证初始化它们。

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

3)所谓编译单元是指产出单一目标文件的那些源码,基本上它是单一源码文件加上其所含入的头文件(#include files)。

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

 

构造/析构/赋值运算

条款05:了解C++默默编写并调用哪些函数(Know what functions C++ silently writes and calls.

C++处理class类,如果你自己没声明,编译器就会为它声明(编译器版本的)一个copy构造函数、一个copy assignment操作符和一个析构函数。此外如果你没有声明任何构造函数,编译器也会为你声明一个default构造函数。所有这些函数都是publicinline

唯有当这些函数被需求(被调用),它们才会被编译器创建出来。

1)default构造函数和析构函数主要是给编译器一个地方用来放置“藏身幕后”的代码,像是调用base classesnon-static成员变量的构造函数和析构函数。注意,编译器产出的析构函数是个non-virtual

2)至于copy构造函数和copy assignment操作符,编译器创建的版本只是单纯地将来源对象的每一个non-static成员变量拷贝到目标对象。

 

条款06:若不想使用编译器自动生成的函数,就该明确拒绝(Explicitly disallow the use of compiler-generated functions you do not want.

1)将copy构造函数和copy assignment操作符声明为private并且故意不实现它们,可以有效阻止人们调用它们。

 

条款07:为多态基类声明virtual析构函数(Declare destructors virtual in polymorphic base classes.

1)对于virtual函数,对象必须携带某些信息,主要用来在运行期决定哪一个virtual函数该被调用。这份信息通常是由一个所谓vptrvirtual table pointer)指针指出。vptr指向一个由函数指针构成的数组,称为vtblvirtual table),每一个带有virtual函数的class都有一个相应的vtbl。当对象调用某一virtual函数,实际被调用的函数取决于该对象的vptr所指的那个vtbl——编译器在其中寻找适当的函数指针。

2)只有当class内含至少一个virtual函数,才为它声明virtual析构函数。

3)polymorphic(带有多态性质的)base classes应该声明一个virtual析构函数。

4)classes的设计目的如果不是作为base classes使用,或不是为了具备多态性,就不该声明virtual析构函数。

 

条款08:别让异常逃离析构函数(Prevent exceptions from leaving destructors.

1)C++并不禁止析构函数吐出异常,但它不鼓励你这样做。

2)析构函数绝对不要吐出异常,如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序。

3)如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。

 

条款09:绝不在构造和析构过程中调用virtual函数(Never call virtual functions during construction or destruction.),因为这类调用从不下降至derived class

1)在base class构造期间,virtual函数不是virtual函数。

 

条款10:令operator=返回一个reference to *this Have assignment operators return a reference to *this.

 

条款11:在operator=中处理“自我赋值”(Handle assignment to self in operator=.

operator=最前面加一个“证同测试(identity test)”达到“自我赋值”的验证目的:

1Widget& Widget::operator=(const Widget& rhs)

{

   if( this == &rhs) return *this;     //证同测试,如果是自我赋值,就不做任何事

   delete pb;

   pb = new Bitmap(*rhs.pb);

   return *this;

}

2Widget& Widget::operator=(const Widget& rhs)

{

   Bitmap* pOrig = pb;

   pb = new Bitmap(*rhs.pb);

   delete pOrig;

   return *this;

}

如果“new Bitmap”抛出异常,pb(及其栖身的那个Widget)保持原状。

3)copy and swap技术

class Widget{

...

void swap(Widget& rhs); //交换*thisrhs的数据

...

Widget& Widget::operator=(const Widget& rhs)

{

Widget temp(rhs); //rhs数据制作一份复件(副本)

swap(temp); //*this数据和上述复件的数据交换

return *this;

}

4)确保当对象自我赋值时operator=有良好行为。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap

5)确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。

 

条款12:复制对象时勿忘其每一个成分(Copy all parts of an object.

1)当编写一个copying函数,请确保(1)复制所有local成员变量;(2)调用所有base classes内的适当的copying函数。

2)不要尝试以某个copying函数实现另一个copying函数,应该将共同机能放进第三个函数中,并由两个copying函数共同调用。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值