Item2:尽量以const,enum,inline替换#define

原因:1, #define ASPECT_RATIO 1.63

      编译错误时产生魔数,应以const double Aspect_Ratio = 1.63替换

   2, #define不能提供作用域,如某个类的常量

      class GamePlayer{

      private:

        static const int = 1024;

        int scores[NumTruns];

      };

      上面的类也可以通过下面的enum实现, 但是此种实现更像是define,因为取NumTruns的地址在此种情况下不合法,define的标识符也不能取地址。

      class GamePlayer{

      private:

        enum{ NumTruns = 5 };

        int scores[NumTruns];

      };

  3, 用inline替换define的函数

    #define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b))

     应以如下inline函数替换

    template <typename T>

    inline void CallWithMax(const T &a, const T &b)

    {

      f(a > b ? a : b);

    }

如果不, 会怎么样:

N.A

Item 3: 尽量使用const

原因:1, 使用const修饰返回值可以降低客户错误造成的意外

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

      可以防止:

      Rational a, b, c;

      (a * b) = c;

    2, const 成员函数的作用是1)确认函数可以作用域const对象。2)操作const对象,pass by reference to const是C++程序的关键,必须有const函数

      关于第二点要说明的是1)const对象调用成员函数,必须为const成员函数,原因见http://www.cnblogs.com/dracohan/archive/2009/11/30/1614089.html

                2)非const对象优先调用非const成员函数,如果无const成员函数,也可以调用该函数对应的const重载函数。

                3)const成员函数和非const成员函数重载,可让非const成员函数调用const成员函数,因为const函数要求更严格。

     3,关于什么函数可以为const,const成员函数可以修改它所处理的对象内的bits,但只有在客户端检测不出的情况下才可以。

Item 4: 类成员的初始化

原因: 

    为保证所有的类成员都被初始化,可以将所有的变量放入初始化队列。

如果不, 会怎么样:

    如果遗漏,则有些变量没有被初始化,会导致不明确行为。

Item5: 1)一个空类,编译器会默默的编写4个函数:默认构造函数,析构函数,copy构造函数,copy赋值操作符

    Empty& operator= (const Empty& rhs){...}

    2) class定义内有reference或者const成员的,编译器拒绝生成copy赋值操作符,因为它也不知道怎么办

    3) 基类的copy 赋值操作符如果是私有的,则编译器不会为派生类生成copy赋值操作符

Item6:可以通过两种方式防止拷贝动作:

    1)将copy构造和copy赋值操作符声明为private,但此种方法不能防止member函数或者friend函数这么做。

    2)可以将copy构造和copy赋值操作符声明为private,并单独生成一个基类。想要此功能的类,私有派生自此基类。此方法的原理是,编译器为派生类生成的默认copy构造和copy赋值操作符都尝试调用基类的对应兄弟,因为是private,必定失败,因为编译器会拒绝。

    

 class Uncopyable{
protected: //允许derive对象构造和析构
Uncopyable(){}
~Uncopyable(){}
private: //不允许copy
Uncopyable(const Uncopyable&);
Uncopyable& operator= (const Uncopyable& rhs);
}; class XXX : private Uncopyable{
...
};

Item 7: 1) 为多态的基类声明virtual的析构函数,否则派生类的部分得不到析构

    2)如果不是多态的基类,不要声明virtual析构函数,影响性能。

    3)不带virtual析构函数的类,不能被用作基类。

Item9: 绝不在析构函数和构造函数中调用virtual函数

原因:  1)因为构造和析构过程中,virtual函数不能下放到派生类中。如果下放,派生类中的变量尚未初始化,将导致未定义行为。

     2) 有一个替代方法,就是让派生类调用基类的版本,但是在调用过程中传递一个派生类的信息给基类,从而加以弥补。

    

class Base{
public:
Base();
Log();
}; class Derived{
public:
Derived();
}; Base::Log(const LogInfo& Linfo)
{
cout << Linfo << endl;
} Base::Base()
{
Log(baseLogInfo);
} Derived::Derived()
{
Log(DerivedLogInfo);
}

如果不, 会怎么样:

    实际调用的虚函数是基类中的版本,不是你想要的。

Item 10: operator= 返回一个reference to *this

原因: 随大流,主要为了实现连锁赋值,如a = b = c;

如果不,会怎么样: 无大碍

Item11: 在写赋值操作符的时候要注意自我赋值的情况

原因:如果不处理,则会导致异常,如下面的写法:

widget& operator= (const widget& rhs)
{
delete m_pointer;
m_pointer = new widget(*rhs.m_pointer);
return *this;
}

   如果是同一对象,第一步就会删除指针,第二步读取异常。有两种方法可以避免问题:

   1)合理安排语句的顺序:

widget& operator= (const widget& rhs)
{
widget* pb = m_pointer;
m_pointer = new widget(*rhs.m_pointer);
delete pb;
return *this;
}

   2) 使用copy-and-swap技术

widget& operator= (const widget& rhs)
{
widget tmp(rhs);
swap(tmp);
return *this;
}

Item12: 如果你自己写了copy构造或者copy赋值函数,那么你就要小心了。

    1)如果增加了成员变量,必须修改copy构造函数和copy赋值函数

    2)如果是派生类,那么记得要调用基类的copy构造函数和copy赋值函数

如果不,会怎么样:

    新增加的成员变量或者基类的成员变量将被默认构造函数初始化,不是要copy的值。

Item13: 以对象管理资源:

    1)autoptr,auto_ptr<Pointee>(createPointee()); //createPointee is a factory function

    2) shareptr, shared_ptr<Pointee>(createPointee());

    3)注意不要在数组身上使用auto_ptr或者share_ptr,因为他们都是执行的delete操作而不是delete[]。

    4)尽量不让工厂类函数直接返回为加工的指针。

    5)copy动作对于auto_ptr来说是交出所有权,赋值后rhs为NULL。对于share_ptr来说是,是增加引用计数。

如果不,会怎么样:

    N.A

Item14: 不是所有的对象都是在堆上被创建的,不一定都是new/delete,所以有时候需要自己写资源管理类,构造和析构函数有可能调用的是lock/unlock操作。

    但是这种类需要注意的是这些类的copy,有几种方法处理copy:

    1) 禁止copy,见Item6

    2)对底层资源使用引用计数

    3)做深拷贝,复制整块内存

    4)交出拥有权,如auto_ptr

如果不,会怎么样:

    会导致多个对象的指针指向同一块内存,当一个对象析构时,其资源已经被释放,其他对象析构将引起未定义行为。

Item15: 提供资源管理对象对底层资源的访问,同时适当提供隐式转换函数

    

class Font{
public:
operator Fonthandle() const {return f;}
private:
Fonthandle f;
};

Item16: 尽量以pass by const reference 代替pass by value

原因: 1) 可以提高效率,不用构造新的对象

    2) 避免对象切割问题

如果不,会怎么样

   N.A

Item30: inline函数不是随便用的

优点: 不用函数开销,比宏好用

缺点:1)增加代码大小。2)改变inline函数,客户需要重新编译。3)不能设置断点调试。

template放在头文件中,如果inline,则所有template生成出来的函数都将是inline的

Item31:将文件间的依存关系将之最低。

方法: 1)使用引用和pointer能办成的事,就不要用对象完成

    2)以class声明式代替class定义式

    3)为声明式和定义式提供不同的头文件。声明式文件中,要么是保存定义式的指针,并在接口中调用之;要么是声明一个基类的abstract类,实现类继承之。

Item34: 区分接口继承和实现继承

   1)声明一个pure virtual函数的目的是为了让derived class只继承函数接口

   2)声明一个普通virutal函数的目的是为了让derived class继承该函数的接口和默认实现

     为了让这种默认继承更加安全,避免在派生类没有声明需要此函数的时候就使用了它的问题,可以用一个基类的pure virutal函数代替,并实现之。派生类实现此pure virtual 函数,从而成为concrete 类,并且调用基类名::函数名()来达到原来普通impure virtual函数的作用。

   3)声明一个non-virtual函数的目的是为了给derived class一个接口和一份强制实现,不得修改。

Item36: 不重新定义继承而来的non-virtual函数

原因:  Base* pb = new Derived;

如果不,会怎么样:通过基类或者派生类的指针调用该函数的时候会造成行为不一致。

Item37: 不重新定义继承来的缺省参数值

原因:缺省参数是编译器确定的,虚函数是运行时才确定的。

如果不,会怎么样: 会产生一个奇葩,派生类函数+基类的默认参数

Item39: private继承

private继承和普通继承有两个不同点:1)private继承而来的派生类不会自动将一个派生类对象转换为一个基类对象

                  2)private继承也叫实现继承,嘛意思呢,就是说基类的接口在派生类里毛都没了,全部封装

Item40: 多重继承

多重继承可用来公共继承几口,私有继承实现。

class CPerson: public IPerson, private PersonInfo{...};

C++-Effective C++ Items的更多相关文章

  1. 异常处理与MiniDump详解(2) 智能指针与C++异常

    write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 讨论新闻组及文件 一.   综述 <异常处理与MiniDump详解(1) C++异常>稍 ...

  2. construction of tuples containing 0 or 1 items

    [construction of tuples containing 0 or 1 items] the syntax has some extra quirks to accommodate the ...

  3. Effective Project Communications

    I was recently invited to speak at a conference in Singapore on Effective Project Communications. I' ...

  4. 小王子浅读Effective javascript(一)了解javascript版本

    哈哈,各位园友新年快乐!愚安好久没在园子里写东西了,这次决定针对javascript做一个系列,叫做<小王子浅读Effective javascript>,主要是按照David Herma ...

  5. [r]Seven habits of effective text editing

    Seven habits of effective text editing(via) Bram Moolenaar November 2000 If you spend a lot of time ...

  6. Effective Tensorflow[转]

    Effective TensorFlow Table of Contents TensorFlow Basics Understanding static and dynamic shapes Sco ...

  7. 04 Effective Go 高效的go语言 重点内容

    Effective Go  高效的go语言 Introduction 介绍 Examples 例子 Formatting 格式 Commentary 评论 Names 名字 Package names ...

  8. <Effective C++>读书摘要--Designs and Declarations<一>

    <Item 18> Make interfaces easy to use correctly and hard to use incorrectly 1.That being the c ...

  9. C++内存管理(effective c++ 04)

    阅读effective c++ 04 (30页) 提到的static对象和堆与栈对象.看了看侯老师的内存管理视频1~3.有点深. 了解一下. 目录 1 内存管理 1.1 C++内存管理详解 1.1.1 ...

随机推荐

  1. [css] line-height

    原文:http://www.zhangxinxu.com/wordpress/2009/11/css%E8%A1%8C%E9%AB%98line-height%E7%9A%84%E4%B8%80%E4 ...

  2. Android控件之Button(按钮控件)和ImageButton(图片按钮控件)

    一.Button和ImageButton特证: 1.共同特证: 都可以作为一个按钮产生点击事件 2.不同特证: Button有text的属性,ImageButton没有 ImageButton有src ...

  3. SDL2.0的SDL_Event事件处理

    SDL_Event事件集合 SDL_AudioDeviceEvent SDL_ControllerAxisEvent SDL_ControllerButtonEvent SDL_ControllerD ...

  4. MIRO校验过程

    一.介绍发票校验是物料管理(MM)系统的一部分.它提供物料管理部分和财务会计, 成本控制和资产管理部分的连接.物料管理模块的发票校验为以下目的服务:它完成物料采购的全过程 - 物料采购从采购申请开始, ...

  5. 能源项目xml文件标签释义--default-lazy-init

    1.spring的default-lazy-init参数 spring在启动的时候,会默认加载会默认加载整个对象实例图,从初始化ACTION配置.到 service配置到dao配置.乃至到数据库连接. ...

  6. DI 之 3.4 Bean的作用域(捌)

    3.4  Bean的作用域 什么是作用域呢?即"scope",在面向对象程序设计中一般指对象或变量之间的可见范围.而在Spring容器中是指其创建的Bean对象相对于其他Bean对 ...

  7. js中的apply和call API

    借用网上的一个例子: fun.call(this,arg1,arg2,arg3) fun.apply(this,arguments) this.fun(arg1,arg2,arg3) 三种方法等效. ...

  8. jmeter 构建一个FTP测试计划

    添加用户 第一步你想做的每一个JMeter测试计划是添加一个 线程组 元素. 线程组告诉 JMeter的用户数量你想模拟,用户应该发送的次数 请求,他们应该发送的请求的数量. 继续添加线程组元素首先选 ...

  9. 发布完ArcGIS地图服务后,服务未启动成功

    今天下午更新地图服务后,服务未启动成功.出来的弹出框警告问题目前应该是ArcGIS Server出了问题,打开ArcCatalog目录,查看GIS服务器下localhost下的服务,只要是今天发布的服 ...

  10. GitHub学习资料

    GitHub账户注册注册了有一年多了(Joined on 13 Apr 2015),一直以来都是本地命令行上传到内网的Git服务器Gitlab.最近正好在学习新的编程语言,所以当初荒废的GitHub想 ...