Chinaunix首页 | 论坛 | 博客
  • 博客访问: 147076
  • 博文数量: 43
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 401
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-31 22:55
文章分类

全部博文(43)

文章存档

2015年(1)

2014年(25)

2013年(17)

我的朋友

分类: C/C++

2014-01-03 22:59:31

条款1:视C++为一个语言联邦

为了理解C++,你必须认识的C++主要次语言为以下四个:

  • C of C++,即C++内的C成分。
  • Object-Oriented C++,这一部分是面向对象设计古典守则在C++上的最直接实施。
  • Template C++,这是C++的泛型编程部分。
  • STL,这是个template程序库。
请记住:
  • C++高效编程守则视状况而变化,取决于你使用C++的哪一部分。

条款2:尽量以const,enum,inline替换#define

    首先我们来看使用const替换#define的好处。
    当你做这样的事:   
   #define    ASPECT_RATIO    1.653
    记号ASPECT_RATIO从未被编译器看见,它在编译器开始处理源码之前就被预处理器移走了,因此ASPECT_RATIO可能并没有进入记号表内。于是当你运用此常量获得一个编译错误信息时,这个错误信息可以会提到1.653而不是ASPECT_RATIO,如果ASPECT_RATIO被定义在一个非你写的头文件内,你肯定会对这个1.653以及他来自何处毫无概念,于是你将因为追踪它而浪费时间。
    解决之道是使用一个常量替换上述的#define定义:
    const double AspectRatio=1.653

   我们再来看看使用enum替换#define的好处,当你的编译器不允许“static整数型class常量”完成"in class初值设定",可以使用“the enum hack”补偿做法其理论基础是:“一个属于枚举类型的数值可权充int被使用”,于是GamePlayer可定义如下:
    class GamePlayer{
    private:
        enum { NumTurns = 5};
        int scores[NumTurns];
        ...
    };
    使用enum hack的理由:
    第一,enum hack的行为某方面说比较像#define而不像const
    第二,它是模板元编程的基础技术,许多代码用到了它,所以看到它时你必须认识它。

    最后,我们来看看使用inline来替换#define的好处,这些#define实现看起来像函数,但是不会招致函数调用带来的额外开销。下面这个宏夹带着宏实参,调用函数f
    //以a和b的较大值调用f
   
    #define    CALL_WITH_MAX(a,b)    f((a)>(b)?(a):(b))
   
    下面让你看看不可思议的事情
 
     int a=5,b=0;
    CALL_WITH_MAX(++a,b);            //a被累加二次
    CALL_WITH_MAX(++a,b+10);        //a被累加一次
   
    在这里,调用f之前,a的递增次数竟然取决于“它被拿来和谁比较
    一个很好的解决办法是使用template inline函数,通过它你可以获得宏带来的效率以及一般函数所有可预料行为和类型安全性。
    template
    inline void callWithMax(const T& a,const T& b)
    {
        f(a>b?a:b);
    }
请记住:
  • 对于单纯变量,最好以const对象或enums替换#defines
  • 对于形似函数的宏,最好改用inline函数替换#defines

条款3:尽可能使用const

    关键字const多才多艺。你可以用它在classes外部修饰global或namespace作用域中的常量,或修饰文件、函数或区块作用域中被声明为static的对象。你也可以用它修饰classes内部的static和non-static成员变量。面对指针,你可以指出指针自身、指针所指物,或两者都是const
    首先先看看const修饰指针,如果关键字const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针自身是常量;如果出现在星号两边表示被指物和指针两者都是常量。
        char greeting[]="Hello";
        char* p = greeting;                        //指针非const,数据非const
        const char* p = greeting;                //指针非const,数据为const
        char* const p = greeting;                //指针为const,数据非const
        const char* const p = greeting;        //指针为const,数据为const
    而STL迭代器的作用就像个T*指针。如果声明一个迭代器为const就像声明一个指针为const一样(即声明一个T* const指针),表示这个迭代器不得指向不同的东西,所指的东西的值是可以改变的,如果希望所指东西不能改动,可以使用const_iterator;
    下面看看const成员函数,const成员函数有两个流行概念:bitwise constness和logical constness。bitwise constness认为成员函数只有在不更改对象的任何成员变量时才可以说是const,而logical constness认为一个const成员函数可以修改它所处理的对象内的某些bits,但只有在客户端侦测不出的情况下可得如此。
    编译器一般是坚持bitwise constness,如果想要做到logical constness可以利用C++的一个与const相关的关键字:mutable,它可以释放掉non-static成员变量的bitwise constness约束。

请记住:
  • 将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。 
  • 编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量性”。
  • 当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复

条款4:确定对象被使用前已先被初始化


请记住:
  • 为内置类型对象进行手工初始化,因为C++不保证初始化它们。 
  • 构造函数最好使用成员初值列,而不要在构造函数本体内使用赋值操作。初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同。
  • 为免除“跨编译单元之初始化次序”问题,请以local static对象替换non-local static对象。




阅读(1203) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~