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. Jquery的普通事件和on的委托事件小案例

    以click的事件为例: 普通的绑定事件:$('.btn').click(function(){})绑定 on绑定事件:$(document).on('click','.btn2',function( ...

  2. 关于javascript的误区

    JavaScript 误区 接触JavaScript两年多遇到过各种错误,其中有一些让人防不胜防,原来对JavaScript的误会如此之深,仅以此文总结一下常见的各种想当然的误区 String rep ...

  3. Java用通配符 获得泛型的协变和逆变

    Java对应泛型的协变和逆变

  4. Mac 实用工具与问题解决

    1.在dock上方的一长溜,被我拖成个方块了 删掉里面的字符,然后按esc 即可! 2.FIT输入法(Fun Input Toy),是苹果操作系统OS X上的免费中文输入法,支持全拼/双拼/全双混拼, ...

  5. 【服务器环境搭建-Centos】系统分区 待续

    df命令查看,显示/dev/vda,而不是sda或hda ,为什么? 虚拟机为了提升性能,一般使用virtio作为磁盘驱动,在虚拟机里面磁盘会显示成vda而不是传统的sda,有什么办法可以让他显示成s ...

  6. ASP.NET C#_HTML练习

    1. textarea和<input type=”text”>的区别是什么?  前者是多行输入框,后者是单行输入框 2. 如何让下拉框菜单支持多选? <select multiple ...

  7. 抛弃优启Grub4dos和PE大多数时间可以这样用

    在能够进入Windows的情况下,Grub4dos和PE大多数时间可以这样用 http://files.cnblogs.com/files/liuzhaoyzz/boot_moban.rar Grub ...

  8. Android相机开发那些坑

    版权声明:本文由王梓原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/168 来源:腾云阁 https://www.qclou ...

  9. SAP 用事务码SQVI 做简单报表 .

    集团计划总监要去德国参展,要一份离当前日期最近的出口欧美国家产品单价. 需要从A903,MARA,KONP,MATK 这4张表里取数. 1)Tcode:SQVI进入,如图 2) 在快速浏览处输入名称: ...

  10. 如何组织较大项目的MVC文件夹结构

    现在还用不到,拷贝下来备用,原文链接 2016 年 9 月 第 31 卷,第 9 期 ASP.NET Core - ASP.NET Core MVC 的功能切分 作者 Steve Smith | 20 ...