第九章 内存模型和命名空间(P301-335)

9.1单独编译

一个程序可以分为三部分:

  • 头文件:结构体声明和函数原型
  • 源代码文件:与结构有关的函数代码
  • 源代码文件:调用与结构有关的函数代码

头文件中经常包括:函数原型,#define或const定义的符号常量,结构声明,类声明,模板声明,内联函数。因为这些都是与定义无关的内容,而内联函数有链接属性。普通函数定义不能放在头文件中,因为如果多个程序调用了该头文件,但都包含了同一个函数定义,会报错。

在一个文件中,头文件只能包含一次,为防止包含多次,可以使用预处理编译指令#ifndef(if not defined):

//头文件:  ***.h
#ifndef COORDIN_H_
...

#endif

表示如果没有创建该名称,则创建,如果已有,则直接忽略,避免了多次创建。

在源程序中包括头文件时:

#include<iostream>  //<>表示这是库文件
#include"***.h"   //""表示这是我们自己创建的头文件

9.2存储持续性,作用域和连接性

c++11中使用四种不同方案来存储数据:

  • 自动存储持续性:执行所属函数或者代码块时创建,执行完后内存被释放
  • 静态存储持续性:函数外定义或者使用关键字static定义的变量,在程序运行整个过程都存在。
  • 线程存储持续性:并行编程中讨论。
  • 动态存储持续性:受用new运算符分配的内存将一直在,直到使用delete运算符释放内存。

作用域描述了名称在文件的多大范围可见(局部变量,全局变量)。
链接性描述了名称如何在不同单元间共享。链接性为外部的名称可以在文件中共享,链接性为内部的名称只能由一个文件中的函数共享

这部分知识不怎么了解,平时用不到,也就不理解,等以后接触到了,再补充详细的。

可以在一个程序引用另一个程序的变量

//1.cpp
int nums = 10; //函数外部,表示全局变量


//2.cpp
extern int nums; //表示从外面引入该变量

如果一个变量名,有一个全局版本,一个局部的,在函数局部只会表现出局部的版本,但如果想在局部打印全局值,在变量名前加一个解析运算符(::)

cout<< ::nums <<endl; //表示其全局版本

函数外声明的变量(全局变量)前加上static,表示该变量只适用于本cpp文件,而不能被其他文件引用

static int mun = 10;
int main()
{
	....	
}

如果是在某个函数中声明变量(局部变量)时,前面加static,表示该变量为静态变量,并且,无论该函数被调用几次,该变量只会在第一次调用时初始化,第二次调用时,该变量值不再是规定的初始化的值,而是上次调用后经变化的值,以此类推,也就是说,该变量不会因为函数调用结束而释放其内存,而是会一直存在。:

void function(int a)
{
	static int n = 0;
	int m = 0;
	n += a;
	m += a;
}

上述函数调用结束时,变量m内存释放,下次调用时再次初始化为0,但n不同,即使函数调用结束,它依旧在,并且值为改变后的,当再次调用时,它的值不会初始化为0,而是之前的n+a。

说明符和限定符

或称之为存储说明符和cv-限定符。
下面是存储说明符:

  • auto(C++11不再是说明符):自动类型推断
  • register:声明中指示寄存器存储(提高访问速度)
  • static:作用在整个文件的声明时,表示内部链接性,即其他文件不可访问。局部声明中,表示存储持续性为静态的。
  • extern:表明是引用变量
  • thread_local:不楚啥玩意
  • mutable:根据const解释含义

下面是cv-限定符:

  • const:不可修改
  • volatitle:表明,即使程序代码没有对存储单元进行修改,其值也可能会发生变化(不太理解,等用到的时候在详细解释)

回到mutable,它表示即使结构或者类变量为const,某个成员依然可以被修改

struct student{
	char name[30];
	mutable int scores;
};

const student s1 = {"kyle",10};
strcpy(s1.name,"smith");  //不可以,错误
s1.scores++; //可以

const之前都是表示常量,但对默认存储类型有些影响,默认情况下全局变量的链接性为外部的,但const全局变量的链接性为内部的,就像使用了static一样,因为,如果在某个头文件中声明const常量,且同一个程序多个文件引用该头文件,即所有文件都会包括该常量的定义,如果链接性为外部,即多个文件声明同一个变量,显然不满足单定义原则,因此表示链接性为内部,即虽然同一个变量名多个文件同时定义,但互不影响。

同变量一样,函数也有链接性。所有函数的存储持续性都为静态的,一直存在,默认情况下,链接性为外部的,可以在文件中共享,可以在原型前使用extern表示该函数是在另一个文件中定义的,可以使用关键字static规定函数链接性为内部的,只能在一个文件中使用。

语言链接性,在函数重载时,虽然我们定义函数名称都相同,但c++编译器执行名称矫正或名称修饰,为重载函数生成不同的符号名称。这里有c语言链接性与c++语言链接性之分。

new运算符,之前只有new运算符开辟一段空间,但不能初始化,现在可在类型后面加上初始值:

int *pi = new int (6);

同理可以给结构体,数组赋值。
如果new找不到请求的内存量,则返回空指针,或者发现异常。并且,new和delete使用时都是调用了相关函数实现其功能的。
定位new运算符:通常new运算符在堆中找到内存块,还有另一种形式,定位new运算符,可以使用我们所指定的位置,要使用该特性时,需要包含头文件new,

char nums [100]; //提前定义一部分内存位置
...
char *p;
p = new (nums) char[5]; //表示在nums内存中开辟出我们所需要的空间

并且要注意,普通的new运算符后需要delete释放内存,但定位new运算符不需要,因为它是在已经开辟的内存中找到相应内存存储数据,所以不需要释放内存。

名称空间

名称空间就是类似于多个不同的区域,在项目中,每个人写的代码不同,但有可能有相同的函数,变量等等,整合就会出现错误,因此采用不同的名称空间,防止名称冲突。

使用关键字namespace创建名称空间:

namespace mk{
	int num;
	double das;
} //创建名称为mk的名称空间,其中包含两个变量。

名称空间可以时全局的,也可以存在另一个名称空间中,但不能位于代码块中,默认情况下,名称空间链接性都是外部的,其他文件可以使用。除了我们定义的名称空间外,还有另一种----全局名称空间,对应文件级声明区域,之前所提得到全局变量都在全局名声空间中。访问名称空间中名称的方法,最简单的就是使用作用域解析运算符:

mk::num = 10;

这样称之为限定的名称,但每次使用太麻烦了因此可以使用using声明和using编译指令。
using声明

using mk::num;  //表示引用mk名称空间中的num变量

可以放在函数中,就是一个局部变量,因此函数中不能有与之名称相同的变量,放在函数外,就是全局变量。
using编译指令

using namespace mk;  //表示调用名称空间mk中的所有名称

这样所有该名称空间名称都为全局的,无论是在函数中函数文件头,这一点与using声明不同,因此,这样可以在函数中声明与名称空间名称相同的变量,二者关系就是局部变量与全局变量(名称空间中的)。

此外,名称空间还支持嵌套,即在一个名称空间中创建另一个名称空间,也可以在名称空间中使用using声明和using编译指令。

同时可以创建没有名称的名称空间:

namespace{
	...
}

这样该名称空间只能在本文件中使用,就像一个全局名称空间,因为没有名称,所以不能被其他文件引用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值