第九章 内存模型和名称空间

1.单独编译

单独编译就是说讲组件函数放在独立的文件中;之后要修改这个函数,只需要重新编译该文件,然后叫它与其他文件的编译版本链接。


这样说可能还是比较抽象;到现在为止大家都很熟悉每个函数例子必备的#include <iostream>了吧;简单的说就是可以把组件函数放在一个叫做头文件的文件中,然后其他函数来#include这个头文件就可以链接到这个头文件里。

书中举了一个包含结构,对结构操作的函数和主函数的例子,我们可以把这个函数写到一个大文件中,也可以写成三个文件:

头文件:包括结构声明,和使用这些结构的函数原型

源代码文件:包含与结构有关的函数的代码

源代码文件:主函数,也是包含调用与结构相关的函数


通常来说,头文件包含以下内容:

使用#define或const定义的符号常量

结构声明

类声明

模板声明

内联函数


注意自己写的头文件要使用#include "self_defined_head.h",而不是#include <self_defined_head>,应为<>编译器将在存储标准头文件的文件夹中查找;而双引号则先在当前目录或源代码目录中查找,如果找不着才会去标准位置查找


在同一个文件中只能将同一个头文件包含一次,但有的时候我们也不知道包不包括了。为避免这个情况发生,我们可以使用书中程序清单9.1的例子中使用的预处理器指令:

#ifndef SELF_DEFINED_HEAD_H_

#define SELF_DEFINED_HEAD_H_

...

#endif

如果读过初中英语肯定一眼就看明白了: 

if SELF_DEFINED_HEAD_H_ not defined, 

define SELF_DEFINED_HEAD_H_, 

end if.

注意头文件的名称要大写,还要用下划线


明白了这一小节,以后写程序就不用把什么都放在一个文件当中了


2. 存储持续性,作用域和链接性

这一节知道这节点名字一看就比较深奥,所以先复习一下内存存储的四种方案:

自动存储, 静态存储,动态存储,以及c++11新增的线程存储

这四种方案的区别就是数据在内存中的保留时间,也叫持续性

自动存储:顾名思义,持续性是自动档,执行是被创建,代码块或函数执行完了就释放

静态存储:一直都安安静静的在那

动态存储:从new出来到delete掉一只存在

线程存储:也顾名思义,其生命周期与所属线程一样长。


什么是作用域呢:作用域就是这个数据/变量在多大范围内可以被调用。作用域一般可以分为局部和全局,局部就是只能在局部有效,全局就是整个程序都可以用。除了变量以为,函数也有作用域,也就是什么时候可以用这个函数什么时候不能。函数的作用域可以是整个类或者整个名称空间


链接性描述了名称如何在不同单元间共享


在默认情况下,在函数声明的函数参数和变量的存储性为自动,作用域是局部(只有函数被执行时能用),没有链接性(不与其他单元共享)

提到自动存储,就可以提一下自动存储的位置:内存中的栈。栈就是先进后出,定义一个新的自动变量,就添加到栈的顶部,如果这个自动变量用完了,就移走


静态存储有3种链接性:外部(可在其他文件中访问),内部(只能在当前文件中访问),无链接性(只能在当前函数或代码区中访问)。区别就是在哪声明了:

在代码块外面声明的链接性就是外部,一般在main()前面或头文件中定义,也叫全局变量

在代码块外面又加了static关键字的就是内部链接性

如果在代码块内不声明然后还使用static限定符的就是无链接性


注意到是要在多个文件中使用外部链接性的变量时,只需在一个文件中包含该变量的定义,但在使用该变量的其他所有文件中,都必须使用关键字extern再声明它一遍。


那么无链接性的静态变量有什么用了。如果一个函数包括一个内部声明的静态变量,在两次函数调用之间,这个静态的值将保持不变。如果初始化了静态局部变量,则程序只在启动时进行一次初始化,以后再调用函数时,则会跳过初始化。


有的时候可以在程序外部声明一个const 变量(不带static关键字),这个时候这个变量夜之魇内部链接性。


函数的存储性都是静态的,即在整个程序执行期间都存在。在默认情况下,函数的链接性为外部,即可以在文件间共享,也可以使用关键字static将函数的链接性设置为内部,使之只能在一个文件中使用


动态存储又和上面的存储不一样了,由new和delete来控制,存储的地方也不一样,叫堆

如果想在其他文件中使用同一个动态存储变量,要在前面加extern关键字


3 名称空间

名称空间就是更好的控制名称的作用域,在不同作用域中可以有相同名称的变量,函数,结构等,例如

namespace A{

int a;

int fun(int)

}

namespace B{

int a;

int fun(int)

}

在程序中要调用A的a,使用A::a = 1;即可。

如果要用a很多次,那么每次都想A::a不是很方便,可以先声明使用的是A的名称空间

using namespace A;

a = 5;

int x = a;

这个叫使用using编译指令。也可以使用using单独使用一个名称,例如

using A::a;

a=5;


在程序外面声明using,就表示这个文件都使用namespace A下的定义,如果在代码块里面,那么就表示这个代码块使用namespace A,代码块外面都就具体情况具体分析了


使用using编译指令导入一个名称空间中所有的名称与使用多个using声明不一样。使用using声明时就好像声明了相应的名称一样。如果某个名称已经在函数在声明了,则不能使用using声明导入相同的名称。然后使用using编译指令时,将进行名称解析,如果使用using编译指令导入一个已经在函数中声明的名称,则局部名称将隐藏名称空间名,就像隐藏同名的全局变量一样。


一般来说,使用using声明比使用using编译指令更安全,因为他只导入指定的名称。如果该名称与局部名称发生冲突,编译器会发出指示

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值