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. Java编程思想学习笔记_2(继承和多态)

    静态初始化: 静态初始化只在必要的时刻进行.(即当程序需要加载类进入内存的时候,执行静态初始化.静态变量和静态代码块的初始化顺序,按照在代码中声明的顺序老执行.例如:如果要执行某个public类,那么 ...

  2. 华为 1.static有什么用途?(请至少说明两种)

    1.static有什么用途?(请至少说明两种) 1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变. 2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问 ...

  3. 网站QQ导航

    <a href="http://wpa.qq.com/msgrd?v=3&uin=[color=Red]361983679[/color]&site=qq&me ...

  4. Sqlserver_自定义函数操作

    use Test go if exists( SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'gettime') AND type in ...

  5. STM8s窗口看门狗

    看看窗口看门狗的框图 从图里看出产生复位信号有2个方式: 1 WDGCR寄存器的T6 由1变0,也就是从此寄存器的值从0x40变成0x3F会产生复位信号: 2 当寄存器WDGCR的值大于WDGWR的时 ...

  6. JSON和php里的数据序列化

    JSON就是一种数据结构,独立于语言 {"1":"one","2":"two","3":" ...

  7. mysql:恢复mysql表结构

    mysql,frm格式恢复mysql表结构,以tuser.frm格式为例   新增数据库,如下,创建数据库名为ab   打开数据库,双击打开数据库   点右键新建表结构   新增表,里面只添加一个字段 ...

  8. jmeter 实时搜索结果

    因为JMeter 2.13你可以得到实时搜索结果发送到后端通过 后端侦听器 使用潜在的任何后端(JDBC.JMS网络服务,€Š) 通过提供一个实现类 AbstractBackendListenerCl ...

  9. Matlab安装记录 - LED Control Activex控件安装

    Matlab安装记录-LED Control Activex控件安装 2013-12-01  22:06:36 最近在研究Matlab GUI技术,准备用于制作上位机程序:在Matlab GUI的技术 ...

  10. 菜单滑动-menu swipe

    http://tympanus.net/codrops/ http://www.idangero.us/sliders/swiper/index.php //触摸滑动