写在前面
他们没有联系只有区别:不同层面上的东西。
- #define: 预处理层面上的替换,不存在于语意层面
- const: 变量的访问控制:只读(read-only)
- static: 变量的作用域控制
——来自B乎某网友
谈谈我的个人理解
#define 宏定义
-
编译预处理期完成,完成文本替代,生成.i文件
-
相当于AKA
#define Kris.吴 吴亦凡
∵吴亦凡 AKA Kris.吴
∴在代码中直接用“Kris.吴”就可以代替“吴亦凡”了
-
在预处理时候做的事,纯粹的字符串替换,不会为它分配空间
-
存在一定缺陷:不安全,没有类型检查(既是优点,也是缺点吧…)
#define pos 3
那我怎么知道pos是int,是float,还是double????
- 一切都要括号
- 整个表达式要括号
- 参数出现的地方也要括号
#define square(x) ((x)*(x))
const 常量
关于本质
- 最直观的理解就是不能被修改,但存在很多细节
- 它实际上就是变量,是需要分配空间的
- 在编译时就需要把值给确定下来
关于指针
Person p1("Fred",200);
// 指针所指对象不可以被修改
const Person* p = &p1;
// 指针所指对象不可以被修改
Person const* p = &p1;
// 指针不可以被修改
Person* const p = &p1;
- 总结
- const在*后面:指针不可以被修改
- const在*前面:指针所指对象不可以被修改
关于字符串
char *s = "hello";
s[0] = 'B';
编译会报
Warning
segment fault : string constant to char*【段错误】运行后会抛
异常
为什么呢????????
因为char *s = "hello";
,相当于是放在代码段
不能被修改的内容
那怎么改呢?
- 在
char
前面加上const
:这样会报error: read-only
(至少知道不能改,安全) char s[] = "hello"
:实质就是把代码段中的字符串,拷贝到堆栈段中,使之可操作
关于类的对象
// 所有成员变量的值都不能被修改
const Person p("Fred",200);
关于函数
- 我们在前面知道,调用函数,是会开辟一个堆栈空间,把一些内容拷贝到堆栈段中的。如果想要使用某个对象,但又想节省空间,我们可以传地址进来。
- 如果担心对象被修改,就可以
const*
来避免修改
- 来看另外一个问题(f()中有const变量)
- a.h:函数f()原型
- a.cpp:函数f()的body
- main.cpp:include"a.h",调用f()
这个时候编译器会去找函数原型,可是这时候他不知道能不能改,他不知道body里有啥,程序就没法正常运行,咋办???
这时候我们只需要void f() const
就可以了,编译器就知道了这个函数保证不会去动成员变量
但是为什么呢???
- 我们来看一个
class A
里的两个函数
void f() {}
void f() const {}
- 提问:他们构成重载吗???——答案是:构成。
为啥??不是说传入参数不一样才可以重载吗????
是的,确实不一样。我们将代码细节还原:
void f(A* this) {}
// 函数const了,表示this是const,这个函数一定不动成员变量
void f(const A* this) const {}
其他
如果这时候有一个:
class A{
const int i;
};
那么它必须被初始化,我们可以在构造函数中,用初始化列表将他初始化。
static 静态
static本地变量 = 全局变量
全局变量
- 文件内可见,文件外不可见
- 变量在全局数据区分配内存(局部变量在栈内,通过new和malloc动态分配的变量在堆里)
- 未经初始化的全局变量会被程序自动初始化为0
局部变量
-
单次初始化(函数内部),持久存储(全局,编译时分配空间)
-
编译器怎么知道有没有被初始化过?
- 个人理解:或许类的内部有一个隐藏的成员变量来记录
-
静态对象的生命周期
- 构造:初始化时,main()前
- 析构:程序结束时
-
如果有多个.cpp的话,全局变量初始化顺序是随机的,如果这些变量之间有依赖的话,会报错
- 解决:去依赖,不用就完了;实在要用,有依赖关系的写在一起
- Java的解决:直接取消全局变量
成员变量
- 对象间共享
- 不能在初始化列表初始化
- 如果写在public内,可以在外部这么用:
cout << A::i << endl;
成员函数
-
对象间共享,只能访问静态成员变量/函数
-
如果类A的public里有个say()函数,可以这么用(与Java类似)
A a;
a.say();
A::say();
- 不可以用this(因为如果直接A::say()的话,没有对象)
谁能用
- 静态类、函数
- main()
C语言:对外不公开的函数
- 函数前加static:只能在所在编译单元中被使用的函数
- 全局变量前加static:只能在所在的编译单元中被使用的全局变量
(编译单元:一般一个.c文件就是一个编译单元)