zoukankan      html  css  js  c++  java
  • static, const 和 static const 变量的初始化问题(定义/声明)

    转自:  https://www.cnblogs.com/xiezhw3/p/4354601.html

    做个记录。

    const 常量的在超出其作用域的时候会被释放,但是 static 静态变量在其作用域之外并没有释放,只是不能访问。

    static 修饰的是静态变量,静态函数。对于类来说,静态成员和静态函数是属于整个类的,而不是属于对象。可以通过类名来访问,但是其作用域限制于包含它的文件中。

    static 变量在类内部声明,但是必须在类的外部进行定义和初始化。

    const 常量在类内部声明,但是定义只能在构造函数的初始化列表进行。

    1 class A {
    2 public:
    3     A(int a) : constNum(a) {}
    4 private:
    5     static int staticNum;
    6     const int constNum;
    7 };
    8 
    9 int A::staticNum = 100;

    从上面的代码可以看出,const 常量的不变形(值不变)只是针对与一个对象来说的,即 同一个类的不同对象的 const 常量的值可以不一样。 

    如果想让 const 常量在类的所有实例对象的值都一样,可以用 static const (const static),使用方式如下:

    1 class A {
    2     const static int num1; // 声明
    3     const static int num2 = 13; // 声明和初始化
    4 };
    5 const int A::num1 = 12; // 定义并初始化
    6 const int num2;  // 定义

    上面两种方式都可以对 const static 常量进行初始化。注意,第 3 行的代码并没有对 num2 进行定义,它只是进行声明。其实这里给了值 13 也没用进行初始化,因为变量必须在定义了以后才进行初始化。但是我们会发现很奇怪的问题,如下:

     1 class A {
     2 public:
     3     const static int num2 = 13; // 声明和【初始化】
     4 };
     5 
     6 int main(int argc, char const *argv[])
     7 {
     8     cout << A::num2 << endl;
     9     return 0;
    10 }

    上面代码的执行结果是 13,也就是说,num2 还没有定义就可以使用了至于 num2 只是声明 没用定义的证明如下

     1 class A {
     2 public:
     3     const static int num2 = 13; // 声明和【初始化】
     4 };
     5 // const int A::num2;
     6 
     7 int main(int argc, char const *argv[])
     8 {
     9     cout << &(A::num2) << endl;
    10     return 0;
    11 }

    在将第 5 行注释后,编译结果如下:

    Undefined symbols for architecture x86_64:
      "A::num2", referenced from:
          _main in a-1e0f08.o
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    [Finished in 0.3s with exit code 1]

    也就是说 num2 还没有定义。在取消注释后成功输出 num2 的地址。说明在 加上  const int A::num2; 后 num2 才被定义

     

    那为什么 num2 还没定义就可以使用了呢,其实因为 num2 是 const 常量,在生成汇编代码的时候并不是在 num2 的地址内取值,而是直接将 num2 【初始化】的时候的那个值替换掉 num2。这也就是用指针改变 const 常量的值的时候 const 常量的字面值并没有变化的原因。这个可以自己去看程序的汇编代码来证明。这个可能在不同的编译器有不同的实现,因为c++标准并没有规定 const 要怎样实现,不同的编译器的实现可能不一样。

     

    另外一个要注意的地方是,在类内部进行 static const 的初始化只能针对于内置类型,比如如下是会报错的:

    1 class A {
    2 public:
    3     const static string str = "str";
    4 };
    5 
    6 const string str;

    所以如果不是必要,一般都是采用类外初始化的形式。那么什么情况下是必要的呢?

    当你的类在编译时需要用到这个类的常量的情况, 例如下面MyClass::MyArray数组的声明(编译过程中编译器一定要知道数组的大小)。

    我们看如下代码:

    1 //MyClass.h
    2 
    3 class MyClass{
    4     public:
    5     static const int MyArraySize = 256;
    6 
    7     private:
    8         int MyArray[MyArraySize];
    9 };

    上面这样是没问题的,但是下面这样就会报错:

     1 //MyClass.h
     2 
     3 class MyClass{
     4     public:
     5     static const int MyArraySize;
     6     static const int MyValue;
     7 
     8     private:
     9         int MyArray[MyArraySize];
    10 };
    11 
    12 //MyClass.cpp
    13 #include "MyClass.h"
    14 
    15 const int MyClass::MyArraySize = 256;
    16 const int MyClass::MyValue = 100;

    在第 9 行,如果 MyArraySize 有初始化的话,会直接用它的值代替。但是这里找不到它的值,所以无法作为数组定义的size。这个时候用前面的方法就会好一点。

     

    最后一个要注意的是,类内的 static const 常量的【初始化】必须用常量表达式,也就是说,这里的【初始化】值必须是一个能直接使用的值。所以如果此时要用函数返回值的话,函数应该是 constexpr 的,如下:

    1 constexpr int fun() {
    2     return 12;
    3 }
    4 
    5 class A {
    6 public:
    7     const static int num = fun();
    8 };
    9 const int A::num;

    //endfile

  • 相关阅读:
    Revolving Digits[EXKMP]
    字符加密Cipher(bzoj 1031)
    Hotaru's problem
    1089 最长回文子串 V2(Manacher算法)
    3172: [Tjoi2013]单词
    3689: 异或之
    3942: [Usaco2015 Feb]Censoring [KMP]
    2795: [Poi2012]A Horrible Poem
    GT考试(bzoj 1009)
    NOIP2016提高组解题报告
  • 原文地址:https://www.cnblogs.com/wybliw/p/10279524.html
Copyright © 2011-2022 走看看