Effective C++ 之static,const以及变量存储位置

一:const

const关键字是一种修饰符,所谓修饰符,就是指在编译器编译过程中,给编译器一些“提示”,就const而言,它告诉编译器,这个变量在编译的过程中是不能被修改的,应用如下:

1)const变量

     const 变量指的是,此变量的值是只读的,不应该被改变。

  • 如果我们在程序中试图修改 const 变量的值,在编译的时候,编译器将给出错误提示。
  • 正因为 const 变量的值在给定以后不能改变,所以 const 变量必须被初始化。(如果不初始化,之后还怎么赋值呢?)如果我们不初始化 const 变量,编译时也会有错误提示。
  • 在C++中通常会被用来替换宏常量(define)即符号变量,符号变量一般是由预编译器处理,变量则有编译器处理,Effective C++一书中说,符号变量也许从未被编译器看到过,因此有时候程序会出现一些编译错误,因此推荐用const变量代替。
  • 类中的const成员变量必须通过初始化列表进行初始化,之后不能改变。
  • 在全局作用域声明的const变量是该文件的局部变量,此变量只能存在于这个文件中,不能够被其他文件访问,若想要被其他文件访问,需要加extern。

2)const对象

   const对象指的是此类的对象不可以被改变,其与const变量并无本质区别,关键是“被改变”的定义。

  在这里,一旦某个类被声明为const对象,那么修改这个类的成员变量以及调用非const成员函数都是不被允许的。

class CDebugModule
{
    public:
        CDebugModule() {};
        ~CDebugModule() {};
    public:
        int m_debugLevel;

    public:
        void SetDebugLevel(int debugLevel) { m_debugLevel = debugLevel;};
        void PrintDebugLevel(void) { cout << m_debugLevel;};
        void PrintDebugLevel_const(void) const { cout << m_debugLevel;};   // const 类成员函数
};

int main( int argc, char *argv[])
{
    const CDebugModule debug;

    debug.m_debugLevel = 10;       // 编译出错:不能直接改变成员变量
    debug.SetDebugLevel(20);       // 编译出错:不能通过成员函数改变成员变量
    debug.PrintDebugLevel();       // 编译出错:不能调用非 const 成员函数
    debug.PrintDebugLevel_const(); // 正常

    return 0;
}

3)const成员函数,将const实施于成员函数的目的,是为了确保这个函数可以用于const对象身上。这一类成员函数之所以重要,是基于两个理由,第一,他们使得class接口比较容易被理解,这是因为,得知哪个函数可以改动对象内容而哪个函数不可以,很重要。第二,他们使得”操作const对象成为可能“。

4)两个函数如果只是常量性不同,则可以被重载。

具体内容请参考博文:

https://www.cnblogs.com/icemoon1987/p/3320326.html

二:static

1)static关键字第一个作用,隐藏

   同时编译多个文件的时候,所有未加static的全局变量和函数都具有全局可见性,别的源文件也能够访问,加了static的变量以及函数只在本文件可见,其他源文件不能够访问,因此static有某种隐藏的特性。

因此我们可以在不同的文件中定义相同名字的变量以及函数,而不用担心他们互相冲突。

2)static第二个变量的作用,保持变量内容的持久(static变量中的记忆功能和全局生存期)

    存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。虽然这种用法不常见。

PS:如果作为static局部变量在函数内定义,它的生存期为整个源程序,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。

3)static的第三个作用是默认初始化为0,其实全局变量也具有这个属性,因为全局变量也存储在静态数据区,在静态数据区,内存中所有的字节默认都是0*00.

   最后对static变量做一个总结,首先static的主要功能是隐藏,其次static变量存放在静态数据去,它具备持久性,且static变量的默认值是0.

面向对象的static:

1)类中的成员加上了static修饰符,就变成了类的静态成员,直接就在内存中分配空间了,和类的实例化没有关系,而普通的变        量是只有在类实例化后才分配内存,依赖于具体的对象存在。静态成员我们可以通过类名加变量名来访问。

2)所有没有加static的成员都是非静态成员.而类被实例化后,可以通过实例化的类名进行访问.非静态成员的生存期决定于该类         的生存期.而静态成员不存在生产期的问题,因为它始终驻留在内存.

    对于非静态的数据成员,每个类的对象都有一份自己的拷贝,而静态数据成员被当作是类的成员,无论这个类被实例化了多少份,静态数据成员始终只有一个拷贝,为该类型的所有对象所共享,静态数据成员对每个对象都是一样的,他得值可以更新。

    感觉这种特性有很大的用处啊。

3)程序中的内存一般分为四个区域,代码区,全局数据区,堆区和栈区。

    一般程序由new产生的动态数据放在堆区,函数内部的自动变量放在栈区。

     静态数据(即使是函数内部的静态局部变量)都存放在全局数据区.

详细解释一下一个C++程序占用的内存分配

1)栈区,由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。通俗来讲就是函       数中的变量参数等等,即{}中的内容。

2)堆区,一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方         式倒是类似于链表。通俗讲就是动态内存分配,

3)全局区(静态区),—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域(RW), 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(ZI)。 - 程序结束后有系统释放 。

4)文字常量区,文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放 (RO)

5)程序代码区,存放函数体的二进制代码。

https://blog.csdn.net/cxsydjn/article/details/79487805

具体请参考博文:

https://www.cnblogs.com/songdanzju/p/7422380.html

https://www.cnblogs.com/sixue/p/3997324.html

猜你喜欢

转载自blog.csdn.net/godqiao/article/details/88343186