难搞的“常宏静”

写在前面

他们没有联系只有区别:不同层面上的东西。

  • #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文件就是一个编译单元)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值