Effective C++ 1. 习惯C++

Effective C++ 1. 习惯C++

毕业设计中途重读了几本以前看过的书,需要做些笔记做日后查阅时使用。
偶然看到 Justin 写的《Effective C++》笔记,为方便就结章转载在此。

========================
Effective C++   C++
书作者:Scott Meyers
原笔记作者:Justin : http://www.cppblog.com/note-of-justin/
========================

Item 1 :C++是一个语言联邦
--------------------------
 tag: c c++组成

 C  
  区块(blocks)、语句(statements)、预处理器(preprocessor)、内置数据类型(built-in data types)、数组(arrays)、指针(pointers)。
  
 Object-Oriented C++
  classes(包括构造、析构)、封装(encapsulation)、继承(inheritance)、多态(polymorphism)、virtual函数(动态绑定)

 Template C++
  泛型编程(generic programming)  Template metaprogramming(TMP,模版元编程)

 STL
  容器(containers)、迭代器(iterators)、算法(algorithms)、函数对象(function objects)
  
 每个语言都有自己的次规则


Item 2  :用const、enum和模板inline推翻#define的统治
---------------------------------------------------
 tag: const enum inline #define
 
 需要定义常量时,不要用#define,改用const修饰的变量或是用enum吧
 要想写一些简短小函数时,别考虑#define啦,改用template+inline吧

 原因是若为浮点变量,用const减小了代码大小,同时还使得封装(encapsulation)变得可行(宏被定义后,在之后的编译过程都有效,除非undef ),而且,在调试的时候,因为const定义的变量是会加在符号表(Symbol Table)的,就比define常量要方便跟踪了(在预处理阶段,常量的名字就已经被替换掉了)
 在一些特定的情况下(编译器不允许“static整数型class常量”完成“in class 初值设定” ),如果不能用const取代#define,就用enum。除了不能获取一个enum的地址之外,这种方法和const的用法其实差不多。
 可以取一个const的地址,不能取一个enum的地址,通常不能取一个#define的地址。
 
 inline函数和宏有个共同的地方,他们都不会有函数调用的栈的开销。再喊上模板(template)来帮忙,就不用去考虑实际调用时的参数类型。


Item 3  :尽可能使用const
--------------------------------------------------
 tag: const  non-const  conceptual constness  mutable
 
 ·首先要知道const可以通用在对象上,函数参数和返回值上,甚至是用在限制函数本身。
 ·const 出现在星号左边,表式被指物是常量;出现在星号右边,指针自身是常量;
 ·两个成员函数如果只是常量性(constness)不同,可以被重载。
 ·const和non-const成员函数的实现等价时,可以用non-const版本调用const版本避免代码重复。
 
    Compilers enforce bitwise constness, but you should program using conceptual constness.

 这里有提到constness(常量性)的两个门派: bitwise学院派和conceptual实用派。
 bitwise constness阵营应该都是很学究的,这里认为如果一个函数被声明是const,你就绝对不能修改对象里的任何成员(static成员除外)。
 主张conceptual constness流的当然都比较好说话,虽然你是const党,但需要的时候,还是应该有例外的嘛。正所谓人无完人,const也没有绝对的const~
 
  conceptual constness可以这样解释:具备conceptual constness的对象/函数,其行为对于该对象/函数以外的数据是const的,不会篡改别人的东东。但是不保证它 不会修改对象/函数内部的成员:当这些成员用mutable修饰的时候,我们可以在一个const函数中修改这些mutable成员的值。
 所以说这样的constness是概念上的,实际上在这样的函数中有可能改变了一些变量的值,只不过没有与它声称的constness矛盾而已。

 用mutable限定的对象,哪怕是在const函数里,一样可以修改!

 和const有关的还有在const和非const对象间的转换问题(用const_cast和static_cast完成两个方向的转换),不过层次太高,我还没能看到有需要用的地方

 const char& operator[](size_t position) const {
  ...
 }
 char& operator[](size_t position)   //调用已经实现的const op[]
 {
      return const_cast<char&> (     //将const op[] 的返回值中移除 const
                  static_cast<const CClass&>(*this)   //将*this转型为 const,指明调用的是const版本的op[]
                  [position] );
 }


Item 4  :对象初始化
--------------------------------------------
 tag:local static , 初始化列表, 赋值(assignment)
 
 ·对于内建的对象类型,手工初始化。
 ·对于对象自身的成员,推荐的方法是在构造函数的初始化列表。
 ·以logcal static 对象替换 non-local static对象,以避免“跨编译单元之初始化次序”问题。
 
 赋值(assignment)的效率要比初始化(initialization)低,因为前者先构造了对象再对他们赋值,在构造的同时就也把值赋了。这里还没加上拷贝构造函数的可能开销,还有一些类型如const变量、引用(reference)是不能用赋值的形式“初始化”的……
 如果在初始化某个对象的时候,有对其他对象是否有初始化的依赖(对不起,这里有点拗口),一定要确保其中所依赖的对象已经初始化完毕。
 
 当不同的对象的初始化存在相互依赖时,某个对象没有初始化有可能导致另外一个对象初始化的失败。
 当初始化涉及到非局部静态对象(non-local static object)时,问题更加明显:非局部静态对象如果定义在不同的文件中,他们就有可能位于不同的编译单元(translation unit),因为这些对象到底谁先被初始化是不可预知的。
 编译单元(translation unit):产出单一目标文件(single object file)的那些源码,通常为单一源码文件加上所包含的头文件。

 解决此类问题的一个方法是:把非局部静态对象转换为局部静态对象(local static object),也就是把它的定义放在一个函数里。然后紧接着在这个函数返回该对象的引用。C++语言规定在调用一个含有局部静态对象的函数时,其中的所有局部静态对象都必须初始化。这个方法就是利用这一特性,将原本对一个非局部静态对象的访问,转换为对一个函数的调用,这个函数会返回该静态对象的引用,并且保证这个对象已经被初始化了。

 如果需要初始化一个非局部静态对象,就把它放到一个函数里,让这个函数简单的返回这个对象的引用。
 

 

你可能感兴趣的:(Effective C++ 1. 习惯C++)