Effective C++ 学习笔记——条款02:尽量以const,enum,inline替换#define

Effective C++ 学习笔记——条款02:尽量以const,enum,inline替换#define,即尽可能使用编译器,少用预处理器。

例如面临如下情况:

#define A 1.653

上述语句中,编译器看不到字符串’A’,只能看到’1.653’,其原因是在预处理阶段就将全文’A’均替换为’1.653’,即所使用的名称并未进入记号表(symbol table),这会使得若文中出现错误,则仅会显示’1.653’而不是’A’,从而找不到错误关键点。
解决方法:
用一个常量(全局常量)替换宏定义(define)。

 const double A = 1.653;

运用全局常量替换宏定义的好处:

首先肯定是会是常量进入记号表内,避免出现上述问题。
其次使用常量可能比使用define宏定义具有较小数量的码,其原因是预处理器会盲目的将’A’全部替换为’1.653’,可能导致目标码(object code)出现多份’1.653’,若使用全局常量则只有一份。

以常量替换 define 时,有两种特殊情况:

  1. 定义常量指针(constant pointers):由于常量定义式通常放在头文件内(方便被多个文件包含),因此有必要将指针声明为const。
    例如:在头文件中定义一个常量 char* 字符串,必须写两次 const:

    const char* const Name = "cc";
    

    但是通常在 C++ 中可采用 string 定义字符串:

    const std::string Nmae = "CC";
    
  2. class 专属常量:声明为类的私有静态成员,这样既保证变量只能被这个类的对象接触到,又不会生成多个拷贝。
    例如:

    class GamePlayer {
       private:
            static const int Num = 5;   //专属于class内,常量声明式
            int score[Num];             //使用该常量
       }
    
  3. 注意:
    因为此处是类的成员声明范围内,所以上面只是变量的声明和初始化,而并非定义,因此如果想获取变量的地址,需要在别处另加定义。这个定义不能有任何赋值语句,因为在类内已经规定为const。
    另外,define不能用来定义class专属常量,也不能提供封装,其原因是一但定义define,其后均可被使用,无法保证私有性。

枚举技巧(the enum hack):

如果需要在一个类内声明一个变量,但是所使用的编译器不允许在声明时赋值初始化,但是紧接着的语句需要使用该变量,例如:

int player;
int scores[player];

此时编译器会报错,为了使player在编译期间有具体数值,则可运用枚举的方法完成:

enum {player = 5};
int scores[player];

因此enum可是充当int类型使用。但enum类型在内存中没有真实地址,相当于一个局部的#define变量。

用内联函数(inline)替换的宏函数(define):

inline函数的作用是,建议编译器把某频繁调用的函数当做内联函数,即在每次函数调用时,直接把函数代码放在函数调用语句的地址,减少堆栈浪费。
宏函数在定义一个函数是,经常会出现歧义,为避免歧义需加入大量括号来保证运算过程,并且也可能存在未知结果。
例如:

#define CALL_MAX(a,b) f((a) > (b) ? (a) : (b))
int a=5, b=0;
CALL_MAX(++a, b);              //a增加了一次
CALL_MAX(++a, b+10);           //a增加了两次

解决办法:采用内联函数代替宏函数:

template<typename T>
inline void callMax(const T& a, const T& b){
    f(a>b ? a:b);
}

总结:

  1. 对于单纯常量,最好以const对象或enums替换#defines。
  2. 对于形似函数的宏(即宏函数,macros),最好改用inline函数替换#define函数。

你可能感兴趣的:(Effective,C++学习笔记,c++)