《Effective C++第三版》读书笔记——实现

来源:互联网 发布:js控制视频播放 编辑:程序博客网 时间:2024/06/07 18:37

5 实现
~~~~~~~

5.1 尽量少做转型动作
=====================
   1. static_cast类似旧式转型,用来强制隐式转换,但它不能将const转换为non-const,这个只有const_cast能办到.
   2. 许多人相信,转型其实什么都没做,只是告诉编译器把某种类型视为另一种类型.这是错误的,类型转换,往往真的令编译器编译出运行期间执行的码.
   3. 在C++中,对单一对象(例如一个类型位Derived对象),不同类型指针指向它的地址可能不一样(例如以Base*指向的地址和Derived*指向的地址可能不一样)!
      实际上,一旦使用多重继承,这事几乎肯定会发生.(*NOTE:这一条在实验时没有成立*)
   4. 对象的布局方式和它们的地址计算方式随编译器的不同而不同,那意味者"由于知道对象如何布局"而设计的转型,在某一平台行得通,在其他平台并不一定行得通.
   5. 我们应该尽可能隔离转型动作,通常是把它隐藏在某个函数内,函数的接口会保护调用者不受函数内部转型动作的影响.

5.2 避免返回handles(reference或指针或迭代器)指向对象内部受保护成分
===================================================================
   1. 调用者可能通过这些handles来更改内部数据
      要解决这个问题,只要在它们的返回类型加上const即可
   2. 要注意handle比所指对象更长寿的风险存在,可能handle指向的是一个废弃的内存空间.

5.3 当异常发生时,需要保持安全
==============================
   1. 异常安全有两个条件:当异常抛出时,带有异常安全性的函数会
      * 不泄露任何资源(可以通过资源管理类来解决)
      * 不允许数据败坏(遵循策略:不要为了某事块要发生而改变对象状态,除非那件事情真的发生了)
   2. 异常安全的三个级别分别是
      1) 基本承诺:
         如果异常被抛出,程序内的任何事物仍然保持在有效状态下,对象是可用的,但无法预知具体是哪个状态.
      2) 强烈保证:
         如果函数不抛异常,就完全成功;如果函数抛异常,则程序还原为原始状态
      3) 不抛异常保证:
         承诺绝不抛异常,总是能够完成她们承诺的功能
   3. 保证强烈保证的一个设计策略师copy and swap:
      为打算修改的对象制作一份拷贝,然后在拷贝上做一切修改,若有任何修改抛出异常,源对象不变.待所有改变成功后,再将拷贝和原对象在一个不抛出异常的操作中置换(swap)

5.4 透彻了解inline
===================
   1. inline只是申请,不是强制命令.大部分编译器拒绝太过复杂的函数inlining,而对virtual函数的调用肯定不会inlining,毕竟inlining的过程是在编译期,而virtual函数的确定是在运行期
   2. inline函数通常一定被放置在头文件内,因为大多数构建环境在编译过程中inlining,而为了将一个函数调用替换为被调用函数的本地,编译期必须知道那个函数的定义.
      同样的道理,templates通常也放置于头文件中,因为它一旦被使用,编译期为了将它具现化,需要知道它长什么样子.
   3. 若通过函数指针的方式调用inline函数,则编译期也会为该函数生成一个outlined函数本地.
   4. 构造函数和西沟函数不是好的适合inline的函数,因为编译期会自动为这些函数生成其他代码,这些代码会大大增加inline的代码量
   5. 要注意:inline函数无法随着函数库的升级而升级.
      而且,大部分调试器都难以调试inline函数

5.5 将文件间的编译依存关系降至最低
===================================
   1. 把类分割成两个classes,一个作为main class提供接口,一个作为Impl class实现接口.其中,main class只内含一个指针成员指向其实现类Impl class.这般设计常称为pimpl(pointer to implementation)
      这样的设计之下,main class的客户就完全和原类的成员相分离了,由于客户无法看到实现的细节,也就不可能写出什么取决于细节的代码,这是真正的接口与实现分离!
      这个分离的关键在于以"声明的依存性"替换"定义的依存性"
   2. 编译依存最小化的本质是:
      让头文件尽可能自我满足,万一做不到,则让它与其他文件内的声明式(*而非定义式*)相依
      * 如果reference或pointer能完成任务,就不要用object
        一个声明就定义出指向该类型的reference或pointer.
        需要定义式才能知道类型的定义
      * 尽量以class声明式代替class定义式
        声明一个函数,而它用到某个class时(返回值或参数类型),并不需要该class的定义;即使函数以by value方式传递参数亦然.
 

  1. class A;              //A的声明式 
  2. A copy(A a);          //这里只需要A的声明就够了 



      * 为声明式和定义式提供不同的头文件
  可以参考C++标准程序库头文件的<iosfwd>,其内涵iostream各组件的声明式
 

本文出自 “暗日” 博客,请务必保留此出处http://darksun.blog.51cto.com/3874064/1148737

0 0
原创粉丝点击