`
nanjingjiangbiao_T
  • 浏览: 2593451 次
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

用const、enum、inline替代#define

 
阅读更多

在C语言程序设计中,define被大量地使用,用来定义常量或者宏,以减少代码重复及提高可维护性。但在C++中,引进了const、enum、inline后,大多数使用define的地方都可以用它们来代替(当然#ifndef、#define、#endif这种条件编译除外)。以下是几点提倡用const、enum、inline而不用define的理由:

1. 定义常量

如果用#define来定义常量,比如#define N 100,在程序在所有用到N地方,编译过程中直接被替换为100,在符号表中并不存在N这个变量,因此对于调试有时可能会造成麻烦。此外,N没有类型可言,因此对于C、C++这种强类型的语言,并不够安全。相反,定义常量最好的方法是用const,如果是定义int,则上述最好用const int N = 100。

2. 类内部常量

对这种情况,用#define是无法实现类内部常量的。因为define没有作用域的概念,只要#define定义后,后面的编译过程任何地方都有效。因此要定义类内部专属的常量,只能用const。

顺便指出下,如果是定义针对类所有实体都共有的常量,则该常量应该同时为static。可以这样定义:

class X
{
public:
	......
	
private:
	const static int N = 100;
};

注意,这时给出的形式仅仅是N的声明式,而非定义式!真正的定义式应该位于cpp文件中,形如:

const static int X::N = 100;

但是,对于static、且仅仅为int型的常量,才可以像上面那样直接在类中声明!如果在程序中不取它们的地址的话,则可以不给出定义式。如果取地址,则必须保证在cpp文件中给出定义式!

(注:《Effective C++,3rd》上作者确实说不可取地址,不过我在VS2010上测试后发现还是可以取地址的.....在gcc编译器(确切说是g++)上明确表示不可取地址,未定义!不得不说,经常发现微软的编译器确认挺奇葩的,不止一次两次。。。。)

对于其他非int 的类型,即使是const static,也不允许直接在类里面给出初始化的声明。如下则为非法的:

class X
{
public:
	......
	
private:
	const static float N = 100.f;
};


3. 针对旧式编译器

旧式的编译器有可能不支持在类内部直接初始化static int型的常量,但有时候又需要用类内的常量来声明数组,如下情况:

class X
{
public:
	......
	
private:
	const static int N = 5;
	int array[N];
};

此时可以利用enum常量为代替const int 来巧妙地实现。

class X
{
public:
	......
	
private:
	enum { N = 5 };
	int array[N];
};

此时的enum常量可以充当int来被使用。但注意的是,enum常量N不可取地址

4. 宏的使用

用define来定义宏,存在一系列的问题:

首先,宏不具有任务类型检查,因此不够安全。

其次,定义宏时,必需为所有的实参加上小括号,否则在调用时可能遇到麻烦。比如:

#define MUL(a,b) a*b
MUL(a+1,b+1);

调用MUL(a+b,b+1)时,实际情况是a+1*b+1,即先计算1*b,再把a和1加进来。因此编译器在预处理时,仅仅是把宏进行原封不动地替换。因此正确写法是:

#define MUL(a,b) (a)*(b)

但即使是这种情况,还是会有一些不可思议的事情发生。比如:

#define Square(a) (a)*(a)
int a = 5;
Square(a++);

执行完Square后,我想绝大多数人的本意肯定是a = 6,但实际却是7,因为a被自增了两次:(a++)*(a++)。用inline函数,即可以像函数一样满足我们的本意:

template<typename T>
inline T Square(const T &a)
{
	return a*a;
}

inline函数既可以像函数一样有实现我们的需求,同时又可以像宏一样,不需要函数调用。因此这种情况下,应该尽可能用inline函数来代替宏的使用。

小结:对于单纯常量,最好以const对象或enum替换#define。

对于形似函数的宏,最好改用inline函数替换#define。

(见《Effective C++,3rd》,条款2)

分享到:
评论

相关推荐

    c++ 尽量不要使用#define 而是用const、enum、inline替换。

    例如:这里程序文件开头有如下#define语句 代码如下: #define N 10 #define PI 3.14 #define MAX 10000 #define Heigth 6.65 … … 假设这里程序运行出错误,而且就是在我们使用这些常量有错误,此时编辑器应该会抛...

    EffectiveC++终稿44__tagged_2019-06241

    Effective C++目 录一.让自己习惯C++ 1条款02:尽量以const,enum,inline替换#define 11)以const替换#defin

    uboott移植实验手册及技术文档

    本文件中的 nand_init()函数,本例使用后者。fs2410.c代码如下: #if defined(CONFIG_CMD_NAND) typedef enum { NFCE_LOW, NFCE_HIGH } NFCE_STATE; static inline void NF_Conf(u16 conf) { S3C2410_...

    程序员面试刷题的书哪个好-effective-cpp-note:EffectiveC++、MoreEffectiveC++和Effective

    程序员面试刷题的书哪个好 Note Of Effective C++ And More Effective C++ 这个文件包含了三本书的详细知识点,想要快速过一下的话可以看这个 ...inline替换#define(Prefer consts,enums, and inlines to #d

    gh0st的socket内核文件

    CLock(CRITICAL_SECTION& cs, const CString& strFunc) { m_strFunc = strFunc; m_pcs = &cs; Lock(); } ~CLock() { Unlock(); } void Unlock() { LeaveCriticalSection(m_pcs); TRACE(_T(...

    C++中友元的实例详解

    C++中友元的实例详解 尽管友元被授予从外部访问类的私有部分的权限,但他们并不与面向对象的编程思想相悖;相反他提高了公共接口的灵活性。 一、友元类 友元声明可以位于公有、私有活保护部分、其所在位置... enum {

    Effective C++ 中文版

    条款02:尽量以const,enum,inline替换#define 条款03:尽可能使用const 条款04:确定对象被使用前已先被初始化 2.构造/析构/赋值运算 条款05:了解C++默默编写并调用哪些函数 条款06:若不想使用编译器自动成生...

    Effective C++(第三版)

    条款02:尽量以const, enum, inline替换 #define prefer consts,enums, and inlines to #defines. 条款03:尽可能使用const use const whenever possible. 条款04:确定对象被使用前已先被初始化 make sure that ...

    PictureEx头文件

    inline int GetPackedValue(enum LSDPackedValues Value); }; struct TGIFAppExtension // application extension block { unsigned char m_cExtIntroducer; // extension introducer (0x21) unsigned char m_...

    Google C++ Style Guide(Google C++编程规范)高清PDF

    Header Files The #define Guard Header File Dependencies Inline Functions The -inl.h Files Function Parameter Ordering Names and Order of Includes Scoping Namespaces Nested Classes Nonmember, Static ...

    一些C面试题,希望能对大家有帮助

    c用宏定义,c++用inline 3.直接链接两个信令点的一组链路称作什么? PPP点到点连接 4.接入网用的是什么接口? 5.voip都用了那些协议? 6.软件测试都有那些种类? 黑盒:针对系统功能的测试白合:测试函数功能,各函数...

    语言程序设计课后习题答案

    2-4 使用关键字const而不是#define语句的好处有哪些? 解: const定义的常量是有类型的,所以在使用它们时编译器可以查错;而且,这些变量在调试时仍然是可见的。 2-5 请写出C++语句声明一个常量PI,值为3.1416;再...

    Practical C++ Programming C++编程实践

    The C++ Preprocessor define Statement Conditional Compilation include Files Parameterized Macros Advanced Features Summary Programming Exercises Answers to Chapter Questions 11. Bit Operations Bit ...

Global site tag (gtag.js) - Google Analytics