当前位置:  编程技术>c/c++/嵌入式

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

    来源: 互联网  发布时间:2014-10-11

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

例如:这里程序文件开头有如下#define语句

代码如下:

#define N 10
#define PI 3.14
#define MAX 10000
#define Heigth 6.65
...
...


假设这里程序运行出错误,而且就是在我们使用这些常量有错误,此时编辑器应该会抛出错误信息。如果该信息提示6.65这里有错误,Ok如果你运气好你正好记得或者程序简单一眼能找到6.65表示什么,如果程序很复杂,而且报出6.65的文件是引用该文件,不记得,那么你会困惑这是什么?或许会花大量时间去追踪6.65是什么?进而定位问题。
为什么错误信息是6.65呢?而不是Heith呢?因为在预编译阶段,已经用5.65来代替Heigth,Height没有进入记号表(system table)内。解决之道是可以使用下面语句进行替换
const double treeHeight=5.68;
   作为一个语言常量,treeHeight肯定会被编译器获知,并且进入记号表内。报出的错误不在是数字而是变量名称,这样有利于定位问题。
这里特别说明一下常量替换#define有两种特殊情况。
   第一个是定义常量指针。这里要将指针定义为常量指针,同时该指针也是指向一个常量,所以是下面的形式:
const char * const HZ="Hang Zhou";
在C++中最好使用string对象来替换掉char*形式:
const std::string HZ ("Hang Zhou");
第二个值得注意的就是class专属常量。首先将作用于限制到类内,必须将其声明为其成员。其次确保此常量至多只有一份实体,必须让它称为static成员。例如:
代码如下:

class People
{
private:
static const int Number=10;
int phoneNumbers[Number];
......
}

这看到的是声明式,而非定义式。通常C++要求你对使用的任何东西提供一个定义式。 或者使用enum,对于形式函数的宏,尽可能用inline或者template来代替。但是如果它是个class专属常量又是static且为整数类型(int,char,bool)则需特殊处理。只要不娶它们地址,则只用声明而不用提供定义式子。但是如果取class专属常量地址,纵使不取其地址编译器就要你提供定义式子。
static const int People::Number
这里定义不设初始值,是因为声明的时候已经获取了初值。

这里可以使用enum完成类似的功能
代码如下:

class People
{
private:
enum { Number = 10 };
int phoneNumbers[Number];
....
}

enum比较像#define而不像const。因为取const的地址是合法的,取一个enum的地址就不合法,取#define地址通常就不合法。所以可以通过enum来实现不让他人取得某个常量的地址。

下面介绍一道笔试题目
代码如下:

#define PRODUCT(a,b) a*b
....
int a=5,b=3,c;
c=PRODUCT(a+3,b+4);

那么c的值为多少?c=5+3*3+4=18而不是程序员预想的56,如果想达到预期的结果必须这样写

#define PRODUCT(a,b) ((a)*(b))
或许这样你还会坚持会写宏函数,因为你想说只用写一个宏函数就能完成int,flaot,double等类型的乘积运算。那么在看看下面例子

#define MAX(a,b) ((a)>(b)?(a):(b))

int a=5,b=3

MAX(++a,b); //a被加了两次

MAX(++a,b+4); //a被加了一次
a被加的结果可能不是预期的,完全可以用template inline函数达到宏的预期效果,并且效率与宏差不多。
代码如下:

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

inline函数是一种编译机制,有点从代码上是看不出来的,但是从程序的执行效率上有差别,通常编译器对函数调用的处理是一种类似中断的方式,即当执行到函数调用语句时,会将当前所有信息存储到寄存器中,在去执行函数的代码,执行完后取回寄存器值,恢复到调用函数开始的状态,继续执行代码。声明为 inline 函数后,编译器不把函数编译成调用函数而是将代码拷贝到被调用的地方。所以效率上要比普通函数高一些,少了存寄存器与取寄存器信息的步骤。
另外需要注意的是inline函数最好写到.h文件中去,或者直接写到类中去。
const允许程序员指定一个语义约束,即不能被改动,编译器会强制实施这项约束。它表示被它修饰的值是不变的。const可以在classes外部修饰global或namespace作用域中的常量,或修饰文件、函数或者static对象以及指针。在const应用在指针中要注意关键字const出现在“*”的什么地方,如果在左边表示被指向的值是常量,如果在右边表示指针自身是常量。出现两边表示两者的功能的并集。这里特别说以下几点:
(1)迭代器中的cosnt
const std::vector::iterator iter=vec.begin(); //相当于iter不能改变

std::vector::const_iterator citer=vec.begin(); //iter所指向的内容无法改变
(2)将函数返回值声明为常量,不仅可以降低因程序员错误造成的不可预料的情况,并且不用放弃安全性和高效性。例如:

const operater *(const &lhs,const &rhs);
if((a * b = c);//本意是if(a*b==c)因程序员马虎而写成这样
如果a和b都是内置类型,此代码就不合理,但是是我们自定义类型,就可能行得通,如果声明返回值是cosnt,就可以预防这么做了。

(3)const成员函数,它是为了确认成员函数可作用于const对象。而且两个成员函数如果只是常量性不同,是可以重载的。成员函数后面跟const,表示该函数不能更改类的成员变量(下面有代码验证,如果尝试对其成员赋值,编译器会爆出错误)。原理就是编译器将其认为是只读变量。并且大多数const对象用于引用传递或者指针传递。
代码如下:

#include
#include

class People
{
public:
People():m_sName(""),m_iAge(0){}
People(std::string name,int age):m_sName(name),m_iAge(age){}
void set(int age)
{
this->m_iAge=age;
}

void set2(int age) const
{
this->m_iAge=age;
}

int get()
{
return this->m_iAge;
}
private:
std::string m_sName;
int m_iAge;
};

int main(int argc,char **argv)
{
People* p=new People("sky",8);
p->set(10);
std::cout

    
 
 

您可能感兴趣的文章:

  • C++ I/O 成员 tellg():使用输入流读取流指针
  • 为什么使用了-l但 仍然不能使用C++类库
  • C++ I/O 成员 tellp():使用输出流读取流指针
  • linux下的C++编译器怎样使用?
  • windows下tinyxml.dll下载安装使用(c++解析XML库)
  • 各位在Unix下开发,使用哪种c++编译器?
  • tcmalloc内存泄露优化c++开源库下载,安装及使用介绍
  • 在Linux下怎么使用C++啊?gcc是C吧?
  • c++类库Boost::bimap(双向映射)介绍及使用实例
  • 请问linux下可以使用c++么?
  • TinyXML(c++下操作xml的库)介绍,下载地址及使用代码举例
  • redhat linux平台下文件正在使用判别C++?
  • 在Python中使用SWIG调用C和C++程序
  • 如何编译一个使用了QT或KDE类的C++程序
  • c++ stl multimap基本操作使用技巧详细介绍
  • Linux下使用C++互斥访问文件+消息队列
  • 请问怎么样使用 Linux下的C++集成开发环境。
  • 使用c++编写gtk程序
  • putty下如何使用gcc编译c或c++程序的资料
  • 大家在UNIX下写程序使用C++么?
  • 是不是只有C++才可以使用STL?
  • Docker官方镜像将会使用Alpine Linux替换Ubuntu
  • MYSQL 批量替换之replace语法的使用详解
  • 使用sh脚本如何替换指定目录下所有文件中的指定字符串
  • 请问:在HP-UX下如何替换正在使用的可执行文件?
  • 关于vi使用文字替换的问题
  • 使用正则表达式替换表情符号核心代码
  • getaddrinfo 中的参数不能使用常量替换?
  • 基于C++字符串替换函数的使用详解
  • SQL SERVER使用REPLACE将某一列字段中的某个值替换为其他的值
  • 求助:使用sh脚本,把文件1.txt中的A都替换成B
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • Python不使用print而直接输出二进制字符串
  • 在测试memset函数的执行效率时,分为使用Cash和不使用Cash辆种方式,该如何控制是否使用缓存?
  • Office 2010 Module模式下使用VBA Addressof
  • 求ibm6000的中文使用手册 !从来没用过服务器,现在急需使用它,不知如何使用! 急!!!!!
  • sharepoint 2010 使用STSNavigate函数实现文件下载举例
  • 请问:在使用oracle数据库作开发时,是使用pro*c作开发好些,还是使用库函数如oci等好一些啊?或者它们有什么区别或者优缺点啊?
  • 使用libpcap读取tcpdump抓取的文件并解析c代码实例
  • 急求结果!!假设一个有两个元素的信号量集S,表示了一个磁带驱动器系统,其中进程1使用磁带机A,进程2同时使用磁带机A和B,进程3使用磁带机B。
  • c/c++预处理命令预#,##使用介绍
  • c#中SAPI使用总结——SpVoice的使用方法
  • 在div中使用css让文字底部对齐的方法
  • 使用了QWidget的程序,如何使用后台程序启动它?
  • Python namedtuple(命名元组)使用实例
  • 共享内存一般是怎么使用的,是同消息队列配合使用么
  • MySQL Workbench的下载安装与使用教程
  • Jsp可否使用带有GUI的JavaBean,如何使用?
  • nginx Windows版相关问题及使用说明
  • asp程序使用的access在Linux下如何使用!
  • 使用java jdk中的LinkedHashMap实现简单的LRU算法
  • 新装的Linux使用root用户不能使用FTP?
  • mongodb介绍及使用场景
  • LINUX下使用Eclipse,如何使用交叉编译器?




  • 特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3