Effective C++读书笔记(1)

  写在前面:之前一直有在写博客,但是总是没坚持下来,感觉博客作为记录自己学习过程的工具还是十分有意义的,故而决定在这儿开始我博客之路的第一步,以C++的学习为始,从得到大量好评的Effective C++ 开始入手,记录自己学习的路程和对一些问题的思考。

effective C++给出了55个改善C++程序的具体建议,并且提出了一些在C++程序设计中经常出现的坑。

建议 01 : 视C++为一个语言集

View C++ as a federation of languages

  早期的C++只是简单的在C上做了面向对象的拓展,发展到今天,C++已经是一个多重泛型编程语言(multiparadigm programming),它支持:

  • 过程形式(procedural)
  • 面向对象形式(object-oriented)
  • 函数形式(functional)
  • 泛型形式(generic)
  • 元编程形式(metaprogramming)

  它由4个子集组成,在书中将其称为"次语言"(sublanguage), 我觉得这个描述不太好,特别是对于其中的泛型编程和STL来说,称为语言总是有些牵强, 我更愿意将它理解为子集的概念, 这4个子集分别为:

  • C,C是C++的基础,所以C++是完全兼容C语言的,当然,有部分的关键字和结构还是有一些区别的,如static关键字C++有了更为复杂的含义。如struct,c++拓展了结构体类型的面向对象特性,等等还有一些其他的,但是主要是拓展性的区别。简而言之,C++就是提供了更为高可用的高效编程,如模板(templates)、异常(exception)、重载(overload)等等,这些在c里面都是没有的。
  • Object-Oriented,这部分就是C++的语言特性相关,包括面向对象的内容: classes(构造函数、析构函数)、封装(encapsulation)、继承(inheritance)、多态(polymorphism)、virtual函数(dynamic binding)、等等...这些就是OO的在C++上的具体实现。
  • Template C++。C++的泛型编程(generic programming)部分,就是C++的函数模板(function template)、类模板(classes template),它们使得泛型编程成为可能
  • STL。STL是C++的标准模板库(Standard Template Library),它实现了一系列通用的容器(containers)、迭代器(itrators)、算法(algorithms)、以及函数对象(function objects),并且以巧妙并且不失高效的设计模式将它们连贯在一起,程序员可以通过使用STL来更为快速的开发高效的程序。

  所以不能简单的讲C++认为是一个语言,而是时刻注意它4个部分不同的规则,并且利用它们来完成更好的设计。

建议 02 :尽量用const, enum, inline来替换 #define

Prefer consts, enums, and inlines to #defines

  这条建议是所有像我一样习惯C开发转向C++开发的程序员,在C程序中,为了让程序更简单修改,减少简易函数的栈开销,常常会使用#define来声明宏变量或者宏函数,但是在C++中,这是不被提倡的,因为#define定义的宏在预编译阶段展开,不会将它描述的变量生成在符号表(symbol table)中,同时,如果使用宏来描述一个浮点型常量,预编译处理器可能会盲目替换代码中对应的浮点数宏变量,虽然这样就不需要为其分配内存,但是事实上代码存储也是需要内存的,反而得不偿失。

  另外, 需要注意的是在类中对const参数的初始化,一般来说,常量值使用声明式在头文件中完成声明。

  可以在声明时初始化:

class GamePlayer {
private:
    static const int NumTurms = 5;   //为了使得常量只有一份实体
    ...
}

或者在类中声明,类外初始化

struct GamePlayer {
private:
    static const int Numturms; //声明式 头文件(.h)声明
    ...
}

const int GamePlayer::Numturms = 5;  //实现文件初始化(cpp/cc)

  一个比较有趣的操作是emum补偿,编译器必须要在编译期间获得数组的大小,有的编译器不允许“static int class” 常量” 完成 "int class 初始化操作" ,就是不能使用class内的static int 常量来作为数组大小,此时就可以曲线救国,使用所谓的“the enum hack”补偿做法,其理论基础是,一个属于枚举类型(enumerated type)的数值可被当做int使用,所以可以这样声明数组:

class GamePlayer {
private:
    enum { Numturms = 5 };   //"the enum hack" 讲NUmturms 作为5的记号
    int scores[Numturms];    //声明数组
}

  enum hack有多种用途,认识它是十分有必要的。enum hack的行为比较类似与#define 而不是const,即它在内存中没有实体,只是作替换功能,所以不能对它取地址,这样也从某种角度实现了一种约束,指针无法指向它,根据编译器的不同,有的编译器会对const对象设定另外的存储空间(没有指针和引用指向的情况下),有的编译器则会,但是使用enum hack却可以保证不会有这部分的额外开销。

  enum hack还是template metaprogramning(模板元编程)的基础技术。


在什么情况下替换

对于单纯的常量,最好使用const 对象或者enum来替换#define
对于类似与函数的宏(macros),最好使用inline函数替换#define,虽然这样编译器会选择是否内联,但是这也是我们想要的。

相关推荐