Effective C++ 第一章(让自己习惯C++)

内置(C-like)类型而言pass-by-value通常与pass-by-reference更高效。但C++类对象中由于构造函数和析构函数的存在,pass-by-reference反而更好。

const 与#define区别

const有更多优点

1 const 常量有数据类型,宏常量没有,编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查。

2 有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。

c++中const可以完全取代宏常量

mutable关键字跟const是相反的,被mutable修饰的变量,将处于可变状态,即使是在一个const函数中。即如一个函数被修饰为const,一般是不可以改变类的成员的,

但如果变量是声明为mutable的,则即使是在这样的函数里也还是可以改变

       windows中句柄与指针的区别:两者是截然不同的概念,Windows用句柄记录系统资源,隐藏系统的信息。即句柄记录windows对象的地址(例 如窗口),这个对象的地址是变化的,句柄就记录这些变化的地址,但是这个地址始终是指向这个资源,而句柄的位置是固定的,所以可以使用句柄来访问 windows资源。


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

         这也可以称之为“宁可以编译器代替预处理器”,对于#define ASPECT_RATIO 1.653  定义的常量ASPECT_RATIO是不会进入符号表的,因为符号表是编译时形成的,#define是预处理器进行处理的,如果运用此获得一个编译期错误,错误提示会提到1.653而不是ASPECT_RATIO,如果这个常量定义在一个非你写的头文件里,则会对该值毫无概念,寻找它而浪费时间。解决这个问题可以用一个常量代替上述的宏:const double AspectRatio = 1.653;这个常量会被编译器看到,会进入符号表。

        还有类专属常量,为了将常量作用域限制于class类内,则必须成为一个类成员,而#define常量是没有作用域的概念的,一旦宏被定义,在它其后的编译过程中就可以被使用。所以#define不提供封装。所以为了确保常量对于这个类最多只有一份实体,则需要使其成为static成员,还有一个方法是使用enum hack,一个属于enum类型的数值可以充当ints使用。

 //取代#define常量
class GamePlayer()
{
private:
    //方法1:static const
    //这是一个声明式而不是定义式,只要不取地址就没有问题,
    //如果要取地址,就需要一个定义式,则可以在实现文件中提供定义式
    static const int NumTurns = 5;

    //方法二:enum hack,行为类似#define,取enum的地址是不合法的,取#define地址也是不合法的
    enum {NumTurns = 5};

    int scores[NumTurns];
};
//定义式,因为已在声明处获得初值,则此处不需要再赋值,这样可以正确访问它的地址
const int GamePlayer::NumTurns; 

           在第二种方法中,如果你不想让别人获得一个指针或引用指向某个整数常量,enum可以实现,还有enums和#define一样不会导致非必要的内存分配。

          令以inline函数替换#define定义的函数。


          条款03:尽可能使用const

          以const修饰stl的迭代器,是声明了一个指针常量,像T* const形式的,而如果使内容不可改变,则应该使用const_iterator指针。

         将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象,函数参数,函数返回值,函数返回类型,成员函数本体。

         如果两个成员函数只是常量性不同,可以被重载。一旦成员函数声明为const,则可以被const对象调用。mutable关键字声明的变量即使在const成员函数中也可以被更改。

        编译器强制实施bitwise constness,但你编写的程序时应该使用"概念上的常量性"

        当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可以避免代码重复,不能让const调用non-const,因为non-const函数可能改变成员变量,这就违背了const函数的初衷。


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

         为内置型对象进行手工初始化,因为C++不保证初始化它们。

         构造函数最好使用成员初始列,而不要在构造函数本体内使用赋值操作。初值列列出的成员变量,其排列次序应该和他们在类中的声明次序相同。

         为免除“跨编译单元之初始化次序”问题,请以local static对象替换non-local static对象。因为C++对于“定义于不同的编译单元内的non-local static对象”的初始化相对次序并无明确定义。所以可以将每个non-local static对象搬到自己的专属函数内(local static),这些函数返回一个reference指向它所含的对象。这类似单例模式,提供一个函数返回静态对象。这样函数内的local static对象会在“该函数被调用期间”“首次遇上该对象之定义式”时被初始化。所以通过函数可以保证被初始化。

你可能感兴趣的:(C++)