《Effective C++》读书笔记

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

可分为四个:

1.   C

2.   Object-Oriented C++

3.   Template C++

4.   STL

 

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

常量定义式通常被放在头文件内

 

Class专属常量,为了将常量的作用域限制在类内,必须让它成为Class的一个成员;而为确保此常量至多只有一份实体,必须让它成为一个static成员。

class GamePlayer{

         private:

                   static const int NumTurns = 5;   //常量声明式

                   int scores[NumTurns]       //使用该常量

                  

};

必须另外提供定义式如下:

const int GamePlayer::NumTurns;     // NumTurns的定义;

这个式子放进一个实现文件而非头文件。由于class常量已在声明时获得初值,因此定义时不可以再设初值。

 

Remember:

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

l          对于形似函数的宏(macros),最好改用inline函数替换#defines

 

条款3:尽可能使用const

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

class Rational {…};

const Rational operator* (const Rational& lhs, const Rational& rhs);

Rational a, b, c;

(a * b) = c;  // a * b的成果上调用operator=

 

const成员函数

1.        使class接口比较容易理解。这是因为,得知哪个函数可以改动对象内容而哪个函数不行。

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


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

 

const成员函数内不能给非mutable成员变量赋值。const成员函数中的(*this)对象是const的。

 

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

 

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

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

l          构造函数最好使用成员初始值列表进行初始化(只调用一次成员变量的copy构造函数),而不是在构造函数本体内使用赋值操作(先调用default构造函数然后再调用copy assignment操作符)。初值列列出的成员变量,其排列次序应该和它们在class中声明次序相同。

l          如果成员变量是constreferences,就一定需要初始值(成员初始值列表来初始化),不能被赋值。

l          static对象是其寿命从被构造出来直到程序结束为止,因此stackheap-based对象被排除。这种对象包括global对象、定义于namespace作用域内的对象、在classes内、在函数内、以及在file作用域内被声明为static对象。

函数内的static对象称为local static对象,其他static对象称为non-local static对象。

l          为免除“跨编译单元之初始化次序”,以local static对象替换non-local static对象。(利用设计模式中的singleton模式实现,C++保证函数内的local static对象会在“该函数被调用期间”“首次遇上该对象定义式”时被初始化。所以如果以“函数调用”<返回一个reference指向local static对象>替换“直接访问non-local static对象”,就获得了初始化的保证。)

 

条款5:了解C++默默编写并调用哪些函数

对于内含reference成员或const成员的classes,如果要支持赋值操作,必须自己定义copy assignment操作符。

 

条款6:若不想使用编译器自动生成的函数,就该明确拒绝

为驳回编译器自动(暗自)提供的功能(如自动提供copy复制函数和copy assignment函数),可将相应的成员函数声明为private并且不予实现。使用象Uncopyable这样的base class也是一种做法。

条款7: 为多态基类声明virtual析构函数

 

条款8:别让异常逃离析构函数

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

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

 

条款34:区分接口继承和实现继承

Class设计继承关系时可以区分为函数接口继承和函数实现继承;

其差异为:

1.   Pure virtual 函数

Derived classes只继承成员函数的接口

2.   Impure virtual 函数

Derived classes 同时继承函数的接口和实现,又能够override它们所继承的实现

3.   Non virtual 函数

Derived classes 同时继承函数的接口和实现,并且不允许覆写任何东西

 

Pure virtual 函数的特性:

1.   必须被任何“继承了它们”的具体class重新声明

2.   在抽象class中通常没有定义(也可以为pure virtual函数提供定义,但调用它的唯一途径是“调用时明确指出class名称”。)

 

允许impure virtual函数同时指定函数声明和函数缺省行为,却有可能造成危险。避免危险,可以切断”virtual函数接口和其“缺省实现”之间的连接。

两种方法:
1.
impure virtual 函数改为一个pure virtual 函数,在其函数中inline调用具有缺省行为的独立函数(分为两个函数实现)

2. pure virtual 函数必须在derived class 中声明,但他们也可以拥有自己的实现(一个函数实现)

 

Remember:

l          接口继承和实现继承不同.public继承之下,derived classes总是继承base class的接口

l          pure virtual函数只是具体指定接口继承

l          impure virtual具体指定接口继承及缺省实现继承

l          non-virtual函数具体指定接口继承以及强制性实现继承

 

待续。。。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值