C++中const 、static、 static const和const static的初始化以及修改问题(3)

作者在 2014-06-12 00:24:58 发布以下内容

.static constconst static的初始化

1)简单说明

首先需要说明,以本人的认识和经验,static constconst static在使用上没有什么区别,可以看作同一类型的两种写法。一个是静态常量,一个是常量静态,都兼具了staticconst的特点,把握好了这一点,下面的内容就不难理解了。

关于这两者,我们就不过多的介绍了,其实也没什么可介绍的了,大家知道它们既有static的特点又有const的特点就行了,下面我们来说明它们的初始化。

2)如何初始化

.先说普遍情况

⒈类外(包括全局、普通函数、main函数中)

直接初始化,即

static const int a=1      //当然也可以写成int static conststatic static

const float b= 1.1        //const也可以互换位置。

  等都可以。

⒉类内的函数中(普通成员函数,构造函数中)

同⒈,可以直接初始化。注意,说在构造函数中可以,是说类似static const floatb= 1.1;这样的语句可编译通过,并不是说在类内可以对static const数据成员初始化 ,当然,我还没发现在构造函数中写类似static const float b= 1.1这样的语句有什么实际用途,只是知道这样写是可以通过编译的。举一小例:

#include<iostream>

using namespace std;

class Myclass

{

public:

    float ceshi()

    {

        static const float c=1.6f;// *)注意这里的f,后面解释

        return c;

    }  

};

void main()

{

   Myclass obj;

    cout<<obj.ceshi()<<endl;//输出1.6

}

简单说一下(*)句的f,因为编译器将1.6默认为double,若不加f(或F),会出现警告:从“double”到“const float”截断,当然不影响运行,我想大家知道就可以了。

⒊作为类的数据成员

前面说过,static const兼有staticconst的双重特点,故不能初始化staticconst数据成员的形式,自然不能拿来初始化static const。即不能直接初始化(当然不包括后面讲到的特例),也不能在构造函数中初始化(无论是在初始化列表还是在函数体中)。由于情况与前边十分类似,这里不再给出代码来举例说明。

既然如此,那就只好在类外初始化,形式同static

eg.

#include<iostream>

using namespace std;

class Myclass

{

public:

    float Get_a()

    {

      return a;

    }

    float Get_b()

    {

      return b;

    }

private:

    static const float  a;

    const static float b;

};

     const float  Myclass::a=1.6f;// f的事情已经解释过   //见注释④

    const float Myclass::b=2.1f;

void main()            

{

  Myclass obj;

    cout<<obj.Get_a()<<endl;//输出1.6

    cout<<obj.Get_b()<<endl;//输出2.1

}

.再说明特殊情况

static const int型 和static const char型数据成员可以在类内初始化!

eg.

#include<iostream>

using namespace std;

class Myclass

{

public:

    float Get_a()

    {

      return a;

    }

    char Get_t()

    {

      return t;

    }

private:

    static const int a=1;

    static const char t='a';

};

void main()

{

  Myclass obj;

    cout<<obj.Get_a()<<endl;//输出1

    cout<<obj.Get_t()<<endl;//输出a

}

如果在private下写static const float a=1.1;是不行的,等号下下划线报错:Error:const float”类型的成员不能包含“in-class initializer,即不能在类内初始化。编译报错:只有静态常量整型数据成员才可以在类中初始化!

至于原因,在下在网上找到的最有说服力的答案是:

===============================================================================

C++11 之前的标准

 只有静态常量整型数据成员,才可以在类中初始化。

 这是因为,当时认为,类定义中的数据定义,是一种声明,不是数据定义。

 当用类定义对象(变量,常量)时候,才开始定义数据。

 静态常量整型数据成员

1)不是对象的一部分

2)可以产生常量表达式,所以可以在类中初始化。---否则,用它作为数组的大小,就不合适了。

 静态常量整型数据成员,能够用来当作常量表达式使用,

 不在内部定义的话,则该常量表达式未定义,就不能使用了。

C++11 非静态成员变量(常量),可以直接初始化,或者在初始化表中初始化。

C++11 中 初始化非静态成员变量(常量),可以看作赋给变量(常量)一个默认值。===============================================================================

除此之外,本人补充一下:

static const int a=1;并不分配内存,编译时直接将a换成1,放到常量表中(关于常量表,本人不是很清楚,读者可以百度,有知道的欢迎告诉我),当然,若对a取地址,则在只读的常量区分配内存。所以,这和类声明不分配内存并不矛盾。至于为什么char型数据成员也可以,我想着应该与char的实现机制有关,char型可以转换成int型,毕竟我们知道字符可以以int型输出其ASSIC码值。不知道我的想法是否正确,欢迎高人批评指正。

 而至于为什么别的类型(比如float)不可以在类内初始化,是因为他们不能像int那样直接进行常量替换,而为什么不能直接进行常量替换,我能给出的解释只能是C++的机制问题,此时不妨参考上面高人给出的解释,从为什么int能来从反面理解为什么其它类型不能。另外,从C++11允许对所有非静态成员变量(常量)在类内初始化更可以看出这是C++本身机制的问题。还是那句话,希望高人指点迷津。对于高人说的“常量表达式”和“数组”,我想可从下面的例子了解一二。例如,在类的private下写:

static const int n=10;

int str[n];//声明数组

不会下划线报错,鼠标移到str下,显示int myclass::str[10];

但如果在Myclass类内的private下写

static const int n;

int str[n];

在类外初始化const int Myclass::n=10;

int str[n];一句中n下下划线报错:Error:表达式必须含有常量值

由此可对高人的话有所理解。但同时,我想说,我觉得通过n来声明数组完全没必要,因为n是不能被修改的,那这样还不如直接写int str[10];从而省去了声明、定义n的事。 或许我举的例子不够恰当,没能体现出那位高人的本意。

还有一点在下想说,那就是关于static const int的事,本人纠结了很久了,包括为什么在类内可以直接初始化它,怎么用,有什么好处,编译器到底为不为它分配内存,什么情况下进行常量折叠,等等等等。我查阅了很多资料(包括国外的编程网站),也请教了很厉害的老师 ,但最终也没能完全弄清楚。一来是在下水平低,二来是各种说法让我莫衷一是,有的说法我可以自己编程验证,但有的暂时还不知道好如何验证。现在只搞清楚了(算是清楚了吧)一点儿,那就是从汇编来看,static const int a=1;这句无论写在哪里,都不会分配空间,但写在函数中(无论什么函数),并把return a时,将会对a分配内存,当然,在任何地方对a取地址或引用a,也将对a分配空间。(读者可以参考我前边提到的《const的思考》,里面比较详尽地给出了什么时候给const数据分配内存,我想static const也是如此)当直接使用a时,例如int d;d=a;cout << Myclass::f;(f为类Myclass下的publicstatic const int),都不分配空间。还有,有人说static const int n=30;#define n 30作用类似,但前者优于后者,原因是前者在使用时只分配一次内存,后者每次使用时都分配内存,但在下经过试验貌似不是这样,两者在直接使用时都不分配内存,通过函数return时,都将分配内存。(以上关于内存分配的讨论很可能有错,因为本人对汇编并不太懂)本人感觉前者的优点主要是可以封装在类中,实现了C++的封装性。 这就是在下所知道的。所以,在下在这里虔诚呼吁,凡是对以上问题明白的,哪怕是略知一二,也万望您不吝赐教。

好了,至此,关于初始化的问题就说到这里,其中也扯进来一些相关问题,可能让读者感到烦乱,而在下这样做的目的主要是把在下知道的都与大家分享,希望让像我一样的初学者能更明白地,较为全面地学到一些东西;同时多多暴露自己的问题和错误,以期在大家的批评指正下提高。由此给您造成的阅读不便,敬请谅解。

下面,在简单说一下const static static const的值的修改问题。

                                                                            (未完待续)

C++ | 阅读 17948 次
文章评论,共0条
游客请输入验证码
浏览37044次
文章分类
文章归档
最新评论