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. Android中view动画

    [1]透明 //点击按钮 实现iv 透明的效果 动画 public void click1(View v) { //1.0意味着着完全不透明 0.0意味着完全透明 AlphaAnimation aa ...

  2. 面向对象的static关键字(类中的static关键字)

    转自:http://blog.csdn.net/xiayefanxing/article/details/7382192 http://www.cnblogs.com/SelaSelah/archiv ...

  3. C# 中的弱引用 WeakReference

    C#中的弱引用(WeakReference)   我们平常用的都是对象的强引用,如果有强引用存在,GC是不会回收对象的.我们能不能同时保持对对象的引用,而又可以让GC需要的时候回收这个对象呢?.NET ...

  4. centos7 最小化安装 无 ifconfig,netstat 的安装

    centos7 最小化安装 无 ifconfig,netstat 的安装 centos7 最小化安装之后,默认是没有 ifconfig,netstat命令的: 我们可以直接使用 yum -y inst ...

  5. CentOS报错:Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=7&arch=x86_64&repo=os&infra=stock32 error was 14: curl#6 - "Could not resolve host: mirrorlist.centos.org; Unknown error"

    今天安装完带图形界面的CentOS 7后,在Terminal中运行yum安装命令时报了以下错误: Could not retrieve mirrorlist http://mirrorlist.cen ...

  6. Columbia遗留问题

    本来Columbia只是按照顺序,导航不可以点击,数组按照顺序push的小东西 在leader的要求下,要变成导航可以点击,无顺序的一团浆糊,经过了大概长达两天(我是不是太适合做程序!)的反复纠结,浆 ...

  7. jQuery+zTree加载树形结构菜单

    jQuery+zTree加载树形结构菜单 由于项目中需要设计树形菜单功能,经过一番捣腾之后,终于给弄出来了,所以便记下来,也算是学习zTree的一个总结吧. zTree的介绍: 1.zTree 是利用 ...

  8. chrome 模拟点击

    实现进入一个页面后触发一个<a>的点击事件. 由于safari和chrome不支持<a>的click()所以需要对浏览器进行判断 var Sys = {};   var ua ...

  9. POC测试——原型验证,降低风险,IT系统销售工作之一

    POC测试,即Proof of Concept,是业界流行的针对客户具体应用的验证性测试,根据用户对采用系统提出的性能要求和扩展需求的指标,在选用服务器上进行真实数据的运行,对承载用户数据量和运行时间 ...

  10. 一段linux shell 代码涉及for循环和if esle

    if [ 0 -ne $# ]; then echo "USAGE: prog [IN]input_file" >&2; exit 1;fisource /etc/p ...