static, const 和 static const 变量的初始化问题
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 函数里面进行一些计算操作。
最新文章
- 【2016-10-25】【坚持学习】【Day12】【WPF】【Telerik】【VirtualtionData 虚拟化数据】
- JS九大内置对象
- .NET 程序集与命名空间
- android TCP 客户端(仅接收数据)
- android 编译 release 签名
- cryptdb中wrapper.lua的分析
- JavaWeb学习记录(二十五)——权限管理总结
- POJ 1308 Is It A Tree? (并查集)
- linux的nohup命令的用法
- 007 字符串(keep it up)
- BP 神经网络
- python魔法方法之构造和析构
- Dockerfile 规范
- ID 生成器 雪花算法
- RANSAC
- 朴素贝叶斯算法简介及python代码实现分析
- Faster_RCNN 3.模型准备(下)
- java_oop_方法2
- js获取按键
- 12 二叉树-链式存储-二叉排序树(BST)