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

本文讨论了在C++中如何使用const和enum替代#define来定义常量,强调了const的正确用法和限制,以及使用inline函数代替宏避免文本替换带来的问题。同时,解释了预处理器在某些场景下仍不可或缺,但应谨慎使用。
摘要由CSDN通过智能技术生成

一. 内容

  1. 这个条款或许改为 宁可编译器替换预处理器 比较好。

  2. 定义常量指针
    有必要将指针(而不止是所指之物)声明为 const。
    例如定义一个常量的 char*-based 的字符串,必须 const 两次。前一次是类型需要,后一次限制为常量。

    const char*  const Author="somebody";
    FFunctionLibrary::Println(Author);//somebody
    Author="anybody";//error:类型只可读
    FFunctionLibrary::Println(Author);//anybody
    

    当然使用 std::string 替换 const char* 更合适。

  3. 为了将常量的作用域(scope)限制在class内,你得让它成为 class 的一个成员(member),而为了确保常量至多只有一份实体。你必须让它成为一个static成员。(Moota:只是需求,不是常量必须为静态)

    class ANonDefine
    {
    public:
    	static const int ConstNumber=10;
    };
    		
    

    但是你所看到的只是 ConstNumber 的声明式,而非定义式。通常情况下C++会要求对你所使用到的任何东西提供一个定义式,但也有特殊情况。

    如果它是个class专属常量又是static且为整数类型(例如ints,chars,bools),只要不取它们的地址,可以直接声明并使用它们。除非如果坚持要取地址或者你的编辑器强制要求看到一个定义式,

    class ANonDefine
    {
    public:
    	static const int ConstNumber=10;
    };
    const int ANonDefine::ConstNumber=9;
    

    注意上面的写法是错误的。
    由于 static 只能定义被初始化一次,请把定义式放在实现(.cpp)文件而非头(.h)文件。
    由于常量已在声明时获得初值,因此在定义它的时候不可以再设初值。

    顺带一提的是我们无法利用 #define 去创建一个 class 专属常量,因为#define并不重视作用域。一旦宏被定定义,它将在之后的编译过程中都有效(除非在某处被 #undef )。这也意味宏没有任何封装性,也就是指没有private #define,public #define。

  4. 当使用常量作为数组大小时,如下的代码是错误的

    class ANonDefine
    {
    public:
    	static const int ConstNumber;
    	 int Array[ConstNumber];
    };
    

    因为编辑器坚持在编译期知道数组的大小。

    解决方法

    • 在ConstNumber声明时就赋值。
    • 使用enum
    class ANonDefine
    {
    public:
    	enum {ArraySize=5};
    	int Array[ArraySize];
    };
    

    其理论基础是:一个属于枚举类型的数值可以充当ints被使用。enum hack 的行为某方面来说比较像 #define 而不是const,有时候这就是想要的,例如取一个 const 的地址是合法的,而取一个 enum 的地址是非法的,而取一个#define 的地址通常也不合法。如果不想别人指针或者引用自己某个整形常量,enum 可以实现这个约束。

  5. #define容易误用
    比如宏函数

    #define Add(a,b) a+b
    int main()
    {
    		
    	FFunctionLibrary::Println(Add(1,2)*Add(3,4));//1
    	system("Pause");
    	return 0;
    }
    

    Add 宏函数执行 a+b 的行为,但宏只是文本替换,像上述的代码实际执行的是 1+2 * 3+4=11,而不是我们期望的(1+2)*(3+4)。这也就是说,你必须记住为宏中的所有实参加上小括号。

  6. inline 而对于替换行为,更好的选择是使用 inline 函数(内联)。

    template <typename T>
    inline T AddUsingInline(const T& a,const T& b)
    {
    	return a+b;
    }
    
  7. 有了const,enum,inline,我们对于预处理器(特别是 #define)的需求降低了,但并非完全消除。#include 仍然是必需品,而 #ifdef,#ifndef 也继续扮演着控制编译的重要角色。目前还没到预处理器全面退出的时候,但你应该明确地慎用它。

二. 总结

  1. 对于单纯常量,最好是以const对象或者enums替换#define。
  2. 对于形似函数的宏(macros),最好改用inline函数替换#defines。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值