在开始之前,先简述一下C++语言。以前一直不知道该怎么定义C++语言,因为用C++写个面向过程的程序也一样可以。现在做一个分析,C++语言是一个多重规则的语言,可以理解为一个由多种语言组合在一起的集合。就好比一个瑞士军刀,里面有好多针对不同功能的工具。
C++基本由四种语言组成:c,OOC++,Template C++和STL。
C就是我们所说的纯C语言,没有模板,没有重载,没有异常;
OOC++就是典型的面向对象编程,所以包括三个基本特征:encapsulation, inheritance and polymorphism。
template C++即泛型编程,威力强大。
STL,它是一个template程序库,功能强大。
不同的语言,有不同的规则,选择对应语言,遵循对应的规则,就能编出高效的程序,比如C语言的内置类型int,pass by value的效率高于pass by reference,而OOC++和template C++的对象,由于构造函数和析构函数的存在,pass by reference比pass by value要高效。同理,STL,它的iterator和函数对象都是基于C指针塑造出来的,所以pass by value更高效,你在STL里找不到reference的应用。
关于C++的分析就这么多,下面继续标题上的point
POINT 3,尽可能的用const, enum替换#define定义的字串或数值常量
首先说用#define定义常量字串,数值存在的问题,比如#deine PI 3.1415926
1. 编译器不知道PI的存在,因为它已经被预处理器改为3.1415926,所以不会将PI加入到symbol table中,编译的时候,我们根本不能靠PI来搜索到它,出问题时很难定位。
2. 没有类型的概念,做数值可以,做字串用也可能,编译器发现不了类型不匹配的错误。
3. 没有常量scope的概念,所以很容易成为一个全局的变量。没有封装变量而言。
下面要说的const就能解决所有上面的问题了,所以用const替代#define定义的字串,数值常量是完全可以的。
const的使用,可能大家也都知道,这个以后会详细说。这里只说一下用const实现的scope变量的限制。以一个class的定义为例:
class A
{
static const int numbers = 5; //这种叫in class 初值设定
int scope[numbers];
...;
}
这里你看到的numbers是声明,而不是定义,通常C++要求我们必须提供定义后才能使用,但是对于statc且为整数类型的变量(int, char, bool等),只要不取它们的地址,我们就可以无需定义直接使用,所以上面的scope数组的numbers可以直接使用。
但是如果编译器不支持这种的话,那我们就不得不写出定义式了,其实也很简单,只是在class 定义外面做如下定义:
const int A::numbers; //这里无需赋值,因为numbers在声明时已获得初值,所以这里不用再赋值。
如果编译器不支持声明in class初值设定,那拿到外面赋值也是一样的,const int A::numbers = 5; 但是这样的话,scope数组里的numbers就不能使用了, int scope[numbers]; 就不能这样定义了,所以这里有另外一种所谓的enum hack的方法,如下:
class A
{
emum {numbers = 5};
int scope[numbers]; //这就没有问题了
...
}
显然,这里的enum起到了一个#define的作用,但是它是由scope限定的,比define更具有安全性和私密性。
这里需要提到一点,通常const 定义的变量,我们是可以访问该变量的地址的,但是enmu和define的定义的变量,我们是访问不了地址的。
总结:常量定义的优先顺序为:const > enum > define,原则就是:能让编译器处理的就不要用预编译器帮忙。
POINT4, 用inline替代#define定义的宏函数
对于另外一种常见的#define使用的方式就是定义宏,如下:
#define MAX_VALUE(a, b) fun( (a) > (b) ? (a) : (b) )
这是个典型的函数宏,这样做的好处是,它可以直接把后面的语句替换到code中,而不会导致function call带来的而外开销,如果你这么做当然就会有这个开销:
void MAX_VALUE(a, b) { func(a > b ? a : b); } //这里有个调用的开销
用define来实现这样的宏有如下的风险:
1. 实参的封闭性,a 必须用小括号包起来,原因大家应该都知道,因为a可能是个表达式。
2. 逻辑混乱,可能出现以下的问题:
int a = 5, b =0;
MAX_VALUE(++a, b); //这里,a会被加两次,最后 a = 7被传给fun
MAX_VALUE(++a, b+10); //这里a被加一次,最后b = 10被传给fun
a被加几次竟然取决于b,逻辑很乱。所以这里我们提出用inline来代替#define,完全可以摆脱这种问题,如下:
template <typename T>
inline void max_value(const T& a, const T& b) { fun( a > b ? a : b); }
同时,因为定义为内联函数,所以编译器当然会把解析过的code直接替换max_value,同样也没有function call的开销,何乐而不为呢?
本节总结:
对于单纯的变量,int,char,string等,尽量用const,enum替代#define
对于函数宏,用inline替代#define
待续... ...