在《Effective C++》一书中的第二个条款,作者让我们尽量以const,enum,inline替换#define,换种说法就是“宁可以编译器替换预处理器”比较好。在一些基础性的文章内,我也是看到了将#define声明的宏视作为常量的作者,这里并不止针对一位作者,而是许多。或许,宏未被编译器所看见,在编译之前就可能编译器已经将所有宏替换了。
为什么使用const代替#define 1.作用域#define并不注重作用域,封装作为面向对象的一部分,这样的操作为使得我们设计的类暴露出来,为了提供封装性,我们可以使用const成员变量代替#define
使用#define写的一段代码
#include#define MAX_SIZE 20 class BankQueue { public: BankQueue() = default; BankQueue(BankQueue&) = delete; BankQueue(BankQueue&&) = delete; int max_size() { return MAX_SIZE; } }; int main() { BankQueue bq; std::cout << bq.max_size() << std::endl; std::cout << MAX_SIZE << std::endl; return 1; }
懂点面向对象编程都知道,max_size是用于获取某个私有成员的接口,但是我们并不能提供private:#define…的操作,为了封装数据,我们应该使用const成员变量代替
使用const成员变量
#includeclass BankQueue { public: BankQueue() = default; BankQueue(BankQueue&) = delete; BankQueue(BankQueue&&) = delete; int max_size() { return max_size_; } private: static const int max_size_ = 20; }; int main() { BankQueue bq; std::cout << bq.max_size() << std::endl; return 1; }
我们对max_size进行了封装,是使用的const而不是#define,此时我们只能通过max_size()获取max_size_了。
2.指针操作#define在编译期前就被编译器全部替换,这样导致我们不能使用指针来对宏操作,例如。
#include#define THREAD_MAX_SIZE 8 int main() { int* p = &THREAD_MAX_SIZE; std::cout << *p; return 1; }
这段代码是错误的,因为THREAD_MAX_SIZE是一个右值,但是操作数必须要是左值,但是我们能通过const将指针成功赋值。
#includeconst int thread_max_size = 20; int main() { const int* p = &thread_max_size; std::cout << *p; return 1; }
注意,指针p声明最前面的const代表所指的数据是一个常量。
3.#define的缺陷既然#define在编译期前就被替换,我们也可以卡它的BUG
#include#define MIN_SIZE 0 #define MAX_SIZE 10 #define LENGTH MAX_SIZE - MIN_SIZE int main() { std::cout << LENGTH << std::endl; return 1; }
输出:10
这个结果在意料之中,那么我们换一个数字试试
#include#define MIN_SIZE 2 #define MAX_SIZE 20 #define LENGTH MAX_SIZE - MIN_SIZE int main() { std::cout << LENGTH / 2 << std::endl; return 1; }
我想找到中间的那个size,不过分吧。
用长度除2,输出结果是19而不是9
编译器在编译期前将整个程序替换为
#include#define MIN_SIZE 2 #define MAX_SIZE 20 #define LENGTH 20 - 2 int main() { std::cout << 20 - 2 / 2 << std::endl; return 1; }
这样错的就很显然了。
总结尽量使用const代替#define!不要犟。
不要将#define认作为常量,它可能从来没被编译器看到过。



