C++之领悟const常量

一、简单常量

C++中的常量具有如下直观的形式:

const long SOME_CONST = 10;

 

清注意:

1、简单的整型常量可以用于指明数组的大小、枚举值以及模板的整型参数等。

         int a[SOME_CONST];                      //指定数组的大小

         enum{x =  SOME_CONST };     //指定枚举值

         frame<int, SOME_CONST , SOME_CONST > frm;  //指定模板的整形参数

2、所有的基本类型都可以用来定义常量,但是浮点常量只能用在浮点字面值使用的地方,例如这种浮点常量不能用于定义数组的大小。

        float FLOAT_CONST = 10.0;       //定义一个浮点类型的常量

        float a[FLOAT_CONST];             //false

        int b[FLOAT_CONST];                //false

3、编译器的影响。编译器会在编译期为这些常量赋值,除非是为了获得这些常量的地址,否则在连接模块中不占用内存。

4、对常量对象的const限定强制转换会引起难以预料的问题。例如考虑下列代码在不同编译器环境下的输出。

        const int w = 10;

        int main()

       {

              int &w = const_cast<int&>(W);

              int const *p = &W;

              w *= 2;

               int const *q=&W;

               int a[W];

               printf("%d,%d,%d,%d\n",W, NUM_ELEMENTS(a), w, *P, *q);

               return 0;

        }

        GCCVisual C++ 6.0的反应是程序崩溃,而在Borland环境下运行结果是1010202020

二、类类型常量

      首先介绍下什么叫类类型常量。类类型常量是指以classstruct以及union关键字之一所声明的类型。

      类类型常量的定义如下:

       class student

       {

              public:

                     student(int id): stdudentId(id){}

              public:

                     int stdudentId;

        };

        const student stu = 3;

 

清注意:

1、类类型常量实例不能被用作字面值来使用。

例如考虑下面的情况:

       int a[stu. stdudentId];            //false

       enum{ x = stu.stdudentId };  //false

       frame<int, stu.stdudentId, stu.stdudentId >frm;   //false

2、常量对象并非是在编译期间进行创建的,而是在运行期间(这种对象的构造函数与普通对象一样,可以在编译期以及连接期的优化步骤中消除掉)。由于他们所具有的的静态作用域存在于任何特定函数的作用域之外,所以他们必须在程序执行期间被创建(和析构)。

      由此这种类类型常量的使用存在三个潜在的缺点:

      首先,特定类型的构造函数和析构函数可能具有显著地运行代价。这个代价被加诸于应用程序/模块和关闭阶段,通常这些代价都是值得关注的。

      其次,全局对象之间可能会出现依赖性的情形。考虑如下情形:

        const student stu = 3;

        extern const student stu3;

        const student stu2 = stu3;

        const student stu3 = stu;

        int main()

      {

             printf(“%d %d %d\n”,stu,stu2,stu3);

             ……

      }

     程序的运行结果是3,0,3,而不是3,3,3。原因是stu2stu3初始化之前就进行了拷贝,由于全局对象栖身于全局内存中,所以能够能够确保得到0初始化。

     最后,如果(非extern)类类型常量对象在编译单元之间被“共享”的话(即声明于一个共享头文件当中),那么每个编译单元实际上接受的是该常量实例的一份单独的拷贝。

三、成员常量

      除了声明在全局和函数作用域中,常量还可以被声明在类作用域中。考虑到

       class  student

      {

             public:

               static const int id = 5;    //成员常量

               static const int num;      //常量静态成员

       }; 

请注意:

1、成员常量跟静态成员的语法类似,除了前者具备变量声明的形式和初始化语句之外。然而这种成员常量仅仅只能够用在整型和枚举型身上,他们又与静态成员不同,因为这种成员常量可以使用在编译期的表达式中,并且无需单独定义。

2、在需要的时候定义常量静态成员,考虑到获取成员常量的地址或者将他们绑定到引用的话,你就需要给出他们的定义。

        int const *p = &student::id;

        int const &q = student::id;

        /* static */ const int student::id;     //这里进行了定义

3、成员常量不能使浮点型的。

      class Maths

     { 

            public:

               static const double pi = 3.1415926;      //成员常量必须是整型

      };

     然而又存在不一致性,浮点型成员常量作为名字空间成员是合法的。

      namespace Maths

     {

            static const double pi = 3.1415926;      //没问题

      }

4、考虑到成员常量并非所有的编译器都支持,成员常量的替代方案:

      首先,使用枚举型代替这种成员常量,缺点是大多数编译器都不允许枚举值大于他们的int类型。

      其次是,定义一个基于静态的方法返回这样的一个常量。例如:

       class Maths

      {

            public:

              static const double pi()

             {

                   return 3.1415926;

              }

       };

     缺点是这样的静态方法返回的常量不是编译期常量,而是运行期间得到的常量。即使这种静态方法在编译期间被优化为一个常量值,他的值依然实在运行期间求出的,因此不能将其用于编译期表达式。例如:

      class X

     {

            static const int i1 = std::numeric_limits<char>::digits;       //没问题

            static const int i2 = std::numeric_limits<char>::pi();   //错误    

     }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值