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

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

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

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

class A {
public:
A(int a) : constNum(a) {}
private:
static int staticNum;
const int constNum;
}; int A::staticNum = ;

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

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

 class A {
const static int num1; // 声明
const static int num2 = ; // 声明和初始化
};
const int A::num1 = ; // 定义并初始化
const int num2; // 定义

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

 class A {
public:
const static int num2 = ; // 声明和【初始化】
}; int main(int argc, char const *argv[])
{
cout << A::num2 << endl;
return ;
}

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

 class A {
public:
const static int num2 = ; // 声明和【初始化】
};
// const int A::num2; int main(int argc, char const *argv[])
{
cout << &(A::num2) << endl;
return ;
}

在将第 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 (use -v to see invocation)
[Finished in .3s with exit code ]

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

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

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

class A {
public:
const static string str = "str";
}; const string str;

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

//MyClass.h

class MyClass{
public:
static const int MyArraySize = ; private:
int MyArray[MyArraySize];
};

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

 //MyClass.h

 class MyClass{
public:
static const int MyArraySize;
static const int MyValue; private:
int MyArray[MyArraySize];
}; //MyClass.cpp
#include "MyClass.h" const int MyClass::MyArraySize = ;
const int MyClass::MyValue = ;

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

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

constexpr int fun() {
return ;
} class A {
public:
const static int num = fun();
};
const int A::num;

当然可以在 fun 函数里面进行一些计算操作。

static, const 和 static const 变量的初始化问题的更多相关文章

  1. Java静态变量的初始化(static块的本质)

    Java静态变量的初始化(static块的本质) 标签: javaclassstring编译器jdk工作 2010-02-06 07:23 33336人阅读 评论(16) 收藏 举报  分类: Jav ...

  2. C++ —— 类中static和const关键字声明变量的初始化方式总结

    在类中声明变量/常量时,经常会用到static.const关键字.对于该变/常量的初始化问题,网上有许多相关文章,但是大多不够完善,或者存在错误.经过实际验证,总结如下: (注明:测试编译平台为VS2 ...

  3. 【C++】const,static和static const类型成员变量声明及其初始化

    1)const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间 void f1() { ; cout<<x<<endl; ...

  4. C++中类中常规变量、const、static、static const(const static)成员变量的声明和初始化

    C++类有几种类型的数据成员:普通类型.常量(const).静态(static).静态常量(static const).这里分别探讨以下他们在C++11之前和之后的初始化方式. c++11之前版本的初 ...

  5. C++ static、const和static const类型成员变量声明以及初始化

    C++ static.const和static const 以及它们的初始化 const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间. sta ...

  6. (转) C++ static、const和static const 以及它们的初始化

    const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间. static表示的是静态的.类的静态成员函数.静态成员变量是和类相关的,而不是和类的 ...

  7. C++ static、const和static const 以及它们的初始化

    转自C++ static.const和static const 以及它们的初始化 const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间. s ...

  8. (转 )C++ static、const和static const 以及它们的初始化

    const定义的常量在函数执行之后其空间会被释放,而static定义的静态常量在函数执行后不会被释放其空间.但不论是Const还是static  他们定义的内容都会随着程序的结束而被系统清楚. sta ...

  9. static数据成员与const数据成员的定义与初始化

    三种数据类型的初始化 1.static int a 的初始化 const int a 的初始化 static const int a的初始化 三种初始化方式 在类外初始化 在构造函数中通过初始化列表初 ...

随机推荐

  1. Java开发23种设计模式

    设计模式(Design Patterns) -- --  -- 可复用面向对象软件的基础 设计模式(Design Patterns)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结. ...

  2. 学习Spring Boot:(九)统一异常处理

    前言 开发的时候,每个controller的接口都需要进行捕捉异常的处理,以前有的是用切面做的,但是SpringMVC中就自带了@ControllerAdvice ,用来定义统一异常处理类,在 Spr ...

  3. AC自动机【萌新文章】

    我这个蒟蒻第一次写博客,有点小激动呢. 主要是最近刚学了AC自动机,学得糟糟糕糕,记录一下,看到dalao们都在写博客,决定自己也写一波[我好水的啦,写的也不好] AC自动机大概就是    Trie+ ...

  4. 【bzoj4016】 FJOI2014—最短路径树问题

    http://www.lydsy.com/JudgeOnline/problem.php?id=4016 (题目链接) 题意 给出一张无向图,求出它的最小路径树,然后求最小路径树上节点数为${K}$的 ...

  5. 破解CobaltStrike3.12(转)

      0x00  概述 CobaltStrike是一款内网渗透的商业远控软件,支持自定义脚本扩展,功能非常强大.前段时间Github上有好心人放出了CobaltStrike3.12的试用版,接着Lz1y ...

  6. 使用IPMI控制/监控Linux服务器

    1       IPMI简述 IPMI提供了很多丰富功能,我使用的功能,说得大白话一点,就是: 1.获取本设备的硬件信息:包括CPU和主板的温度.电压.风扇转速. 2.在设备A上,通过命令,控制远程设 ...

  7. mac 安装 pecl

    下载 pear curl -O http://pear.php.net/go-pear.phar sudo php -d detect_unicode= go-pear.phar 配置和安装 pear ...

  8. php 性能优化

    php 性能测试工具 ab(Apache Benchmark) ab 是由 Apache 提供的压力测试软件.安装 apache 服务器时会自带该压测软件. 如何使用: ab -n1000 -c100 ...

  9. Linux下安装Python3和django并配置mysql作为django默认服务器

    我的操作系统为centos6.5 1  首先选择django要使用什么数据库.django1.10默认数据库为sqlite3,本人想使用mysql数据库,但为了测试方便顺便要安装一下sqlite开发包 ...

  10. K8S发布解释型语言应用的最佳实践

    说明 我们知道,k8s在发布编译型语言的应用时,几乎不用多考虑,就会选择将编译好jar/war包(java语言)或者二进制文件(golang/c++)直接打到镜像当中,生成新的应用镜像,然后将镜像推到 ...