C++中常量的定义与使用
2012-02-02 01:00
281 查看
在C中,我们定义一个常量,通常会使用宏来定义:
#define int CONST_VALUE 100
由于C++是兼容C的,所以,在C++中,这种定义常量的方式同样允许,而且,在C++中又增加了两种定义常量的方式:
(1)在常量定义的时候使用关键字const
(2)定义一个enum类型,使用其成员表示一个常量
所以,在C++中有三种方式可以定义一个常量,但是,三种定义常量的方式背后的原理是不同的。
当我们使用#define定义一个常量的时候,其表示的方式是由预处理器处理的。预处理器是在编译器被调用之前调用的一个独立的程序,预处理器的作用主要是删除注释,包含相关文件、以及相关的宏代替等。在宏代替中,又包含了两种代替,一种是函数的代替,另一个则是我们上面所说的常量的代替。也就是说,在C++编译器开始编译程序的时候,我们使用宏定义的常量已经被预处理器给处理了一次。这里的处理方式很简单,只是单纯的将代码中的宏名替换为我们所定义的常量值,对于我们的例子来说,就是将代码中的CONST_VALUE替换成100,当编译器开始编译程序的时候,我们的代码中已经看不到我们使用的CONST_VALUE这个常量名,取而代之的是它的值100。或许有人会说,这很正常啊,本来我们就是用的100这个常量值。但是有一点必须注意,当我们的编译器开始编译程序的时候,他可能不知道CONST_VALUE这个变量,因为在编译器开始处理代码的时候,CONST_VALUE这个变量名已经被预处理器给替换成它的值100,所以,CONST_VALUE这个值压根就没有进入到记号表(symbol
table)。如果我们使用这个常量的代码段出现了一个错误,错误信息会提到100,而不是变量名CONST_VALUE,而恰恰此时,如果我们使用的这个常量是其他人所写的,我们仅仅是使用这个常量名的话,则会产生疑惑:这个值代表什么?从哪里来的呢?从而在调试程序的时候带来不必要的麻烦。归根到底,则是,使用宏定义的常量没有进入到记号表中。
注:一直没有找到测试提示编译错误使用值而不是宏名的方法,如果有朋友有测试代码,望不吝指教。
然而,当我们使用cosnt或者enum定义一个常量的时候:
const int Const_Value = 100;
或
enum
{
CONST_VALUE = 100,
};
则在预处理阶段不会将我们的变量名给替换成相应的常量值,所以,在编译器处理代码的时候,会将相应的常量名放入到记号表中,如果在编译期出现错误,则会指出其常量名而不是用100这个值。这样就避免了上面出现的困惑。
因为C++是一门面向对象编程语言,不可避免的我们会使用类来进行相关功能的实现。此时,如果我们定义一个类如下:
class CTest
{
public:
CTest() {}
~CTest() {}
private:
int arr_test[100];
};
我们定义的类中,有一个数据成员,它是一个由100个元素组成的整型数组。如果我们想在代码中对数组大小进行控制,可以使用一个常量代替数组大小。则修改如下:
class CTest
{
public:
CTest() {}
~CTest() {}
private:
int arr_test[COSNT_VALUE];
};
其实这样,我们的目的已经达到了,我们使用常量值CONST_VALUE代替了显示的数组大小100。但是,这样做是不是有些不妥呢?
我们知道,C++是一门面向对象编程语言,其私有数据成员仅在这个类内部的成员函数被访问(这里只考虑不存在继承体系的类以及没有友元的情况)。然后我们回到上面的例子,数组arr_test是一个私有成员,如果我们使用一个宏定义一个常量,然后用这个常量表示数组的大小,那么我们就可以在类的外部去操纵这个数组大小。这种情况下,
使类不再具有严格意义上的封装性,这是因为#define并不重视封装性。此时,我们需要用一个仅可以在类内部定义的常量来表示数组的大小。所以我们需要一个这样的常量,他可以在类的内部定义,用来表示数组的大小,而且它应该不占用内存空间,因为这个常量仅仅是用来表示类的大小,没有其他的用处,于是便有了”类专属常量“这个概念:
类专属常量的定义方法是在常量的定义前面加static关键字。这时,我们的类已经成了这个样子:
class CTest
{
public:
CTest() {}
~CTest() {}
private:
static const int CONST_VALUE = 100;
int arr_test[CONST_VALUE];
};
我们知道,static类型的变量是存储在静态存储区的,它在类中不占用内存空间,如果我们sizeof(CTest)得到的值是400,仅仅是数组arr_test的大小。这正符合我们当初的意图。至于为什么不直接用const类定义数组的大小,那是因为,cosnt与引用类型的变量必须在成员初始化列表中进行初始化,也就是说,我们编译时是不会知道我们定义的常量的值的,只有我们真正生成这个类一个对象的时候,我们所定义的常量值才知道大小。但是,作为一个数组的大小,必须是在编译器可知的一个值。如果我们直接用const去定义一个常量,则会报错。
由此我们可以,使用#define不仅不能够定义一个类的专属常量,也不具有良好的封装性。当我们需要一个这样的常量的时候,应该避免使用宏定义,取而代之的是用类的专属常量。
同样使用enum也能达到同样的效果,我们将在另外的文章中讨论这一个问题。
#define int CONST_VALUE 100
由于C++是兼容C的,所以,在C++中,这种定义常量的方式同样允许,而且,在C++中又增加了两种定义常量的方式:
(1)在常量定义的时候使用关键字const
(2)定义一个enum类型,使用其成员表示一个常量
所以,在C++中有三种方式可以定义一个常量,但是,三种定义常量的方式背后的原理是不同的。
当我们使用#define定义一个常量的时候,其表示的方式是由预处理器处理的。预处理器是在编译器被调用之前调用的一个独立的程序,预处理器的作用主要是删除注释,包含相关文件、以及相关的宏代替等。在宏代替中,又包含了两种代替,一种是函数的代替,另一个则是我们上面所说的常量的代替。也就是说,在C++编译器开始编译程序的时候,我们使用宏定义的常量已经被预处理器给处理了一次。这里的处理方式很简单,只是单纯的将代码中的宏名替换为我们所定义的常量值,对于我们的例子来说,就是将代码中的CONST_VALUE替换成100,当编译器开始编译程序的时候,我们的代码中已经看不到我们使用的CONST_VALUE这个常量名,取而代之的是它的值100。或许有人会说,这很正常啊,本来我们就是用的100这个常量值。但是有一点必须注意,当我们的编译器开始编译程序的时候,他可能不知道CONST_VALUE这个变量,因为在编译器开始处理代码的时候,CONST_VALUE这个变量名已经被预处理器给替换成它的值100,所以,CONST_VALUE这个值压根就没有进入到记号表(symbol
table)。如果我们使用这个常量的代码段出现了一个错误,错误信息会提到100,而不是变量名CONST_VALUE,而恰恰此时,如果我们使用的这个常量是其他人所写的,我们仅仅是使用这个常量名的话,则会产生疑惑:这个值代表什么?从哪里来的呢?从而在调试程序的时候带来不必要的麻烦。归根到底,则是,使用宏定义的常量没有进入到记号表中。
注:一直没有找到测试提示编译错误使用值而不是宏名的方法,如果有朋友有测试代码,望不吝指教。
然而,当我们使用cosnt或者enum定义一个常量的时候:
const int Const_Value = 100;
或
enum
{
CONST_VALUE = 100,
};
则在预处理阶段不会将我们的变量名给替换成相应的常量值,所以,在编译器处理代码的时候,会将相应的常量名放入到记号表中,如果在编译期出现错误,则会指出其常量名而不是用100这个值。这样就避免了上面出现的困惑。
因为C++是一门面向对象编程语言,不可避免的我们会使用类来进行相关功能的实现。此时,如果我们定义一个类如下:
class CTest
{
public:
CTest() {}
~CTest() {}
private:
int arr_test[100];
};
我们定义的类中,有一个数据成员,它是一个由100个元素组成的整型数组。如果我们想在代码中对数组大小进行控制,可以使用一个常量代替数组大小。则修改如下:
class CTest
{
public:
CTest() {}
~CTest() {}
private:
int arr_test[COSNT_VALUE];
};
其实这样,我们的目的已经达到了,我们使用常量值CONST_VALUE代替了显示的数组大小100。但是,这样做是不是有些不妥呢?
我们知道,C++是一门面向对象编程语言,其私有数据成员仅在这个类内部的成员函数被访问(这里只考虑不存在继承体系的类以及没有友元的情况)。然后我们回到上面的例子,数组arr_test是一个私有成员,如果我们使用一个宏定义一个常量,然后用这个常量表示数组的大小,那么我们就可以在类的外部去操纵这个数组大小。这种情况下,
使类不再具有严格意义上的封装性,这是因为#define并不重视封装性。此时,我们需要用一个仅可以在类内部定义的常量来表示数组的大小。所以我们需要一个这样的常量,他可以在类的内部定义,用来表示数组的大小,而且它应该不占用内存空间,因为这个常量仅仅是用来表示类的大小,没有其他的用处,于是便有了”类专属常量“这个概念:
类专属常量的定义方法是在常量的定义前面加static关键字。这时,我们的类已经成了这个样子:
class CTest
{
public:
CTest() {}
~CTest() {}
private:
static const int CONST_VALUE = 100;
int arr_test[CONST_VALUE];
};
我们知道,static类型的变量是存储在静态存储区的,它在类中不占用内存空间,如果我们sizeof(CTest)得到的值是400,仅仅是数组arr_test的大小。这正符合我们当初的意图。至于为什么不直接用const类定义数组的大小,那是因为,cosnt与引用类型的变量必须在成员初始化列表中进行初始化,也就是说,我们编译时是不会知道我们定义的常量的值的,只有我们真正生成这个类一个对象的时候,我们所定义的常量值才知道大小。但是,作为一个数组的大小,必须是在编译器可知的一个值。如果我们直接用const去定义一个常量,则会报错。
由此我们可以,使用#define不仅不能够定义一个类的专属常量,也不具有良好的封装性。当我们需要一个这样的常量的时候,应该避免使用宏定义,取而代之的是用类的专属常量。
同样使用enum也能达到同样的效果,我们将在另外的文章中讨论这一个问题。
相关文章推荐
- C++使用之常量的定义
- 从Java到C++——常量值的使用和定义
- C++使用之常量的定义
- 从Java到C++——常量值的使用和定义
- C++使用之常量的定义
- Java开发中有时候用十六进制定义常量有什么好处?什么时候考虑使用十六进制?
- C++文本查询程序 不要定义类和智能指针管理数据 C++Primer练习12.28 使用vector,map,set容器保存来自文件的数据并生成查询结果
- C/C++:[2]enum-枚举量声明、定义和使用
- 定义c/c++全局变量/常量几种方法的区别(转载)
- [c++]使用前后缀表示常量的类型
- c++重载函数定义和使用
- C++中“头文件”的定义和使用
- 17、C#中的常量和结构的定义与使用
- C++ 中常见预定义宏的使用
- 提高Java代码质量:使用枚举定义常量(转)
- [置顶] 使用const定义常量,inline定义小型函数
- java常量和变量的定义规则,变长参数的使用
- FOUNDATION_EXPORT的使用(定义常量和define类似)
- C/C++]可变参函数的定义和使用【转】
- Effective Modern C++ 条款22 当使用Pimpl Idiom时,在实现文件中定义特殊成员函数