C++-note2

-动态存储分配
-名称空间


单独编译

一般来说,会把程序分为三部分:
头文件:包含结构声明和使用这些结构的函数的原型
源代码文件:包含于结构有关的函数的代码
源代码文件:包含调用与结构相关的函数的代码

使用自己编写的编写的头文件使用“ ”而不再使用<>.

1
2
3
4
5
6
7
//头文件的编写
#ifndef HEAD_H_
#define HEAD_H_
...
#endif


自动存储持续性
在默认的情况下,函数声明的函数参数和变量的存储持续性为自动,作用于为局部,没有链接性。当程序开始执行这些变量所属的代码块时,将为其分配内存。当函数结束时,这些变量都将消失。

如果在代码块中定义了变量,则该变量的存在时间和作用于将被限制在该代码块内

如果存在两个同名的变量,其中一个位于外部代码块中,而另一个位于内部代码块中。在这种情况下,程序执行内部代码块中的语句时,解释为内部代码块变量。

一般程序使用栈来管理自动变量。


静态持续变量
编译器分配固定的内存块来存储所有的静态变量,这些变量在整个程序执行期间一直存在。

1
2
3
4
5
6
7
8
//要创建链接性为外部的静态持续变量,必须在代码块外面声明它
//要创建链接性为内部的静态持续变量,必须在代码块外面声明并且加上static修饰
//要创建没有链接性的静态持续变量,必须在代码块内部声明它并且加上static修饰
int global=1000; //链接性为外部的静态持续变量
static int one_file=50; //链接性为内部的静态持续变量
void funct1(int n){
static int count=0; //没有链接性的静态持续变量
}

如果要在多个文件中使用外部变量,只需在一个文件包含该变量的定义,但在使用该变量的其他所有文件中都必须使用关键字extern声明它

1
2
3
4
5
6
7
8
9
10
//file1.cpp
extern int cats=20;
int dogs=22;
...
//file2.cpp
extern int cats;
...
//file3.cpp
extern int cats;
extern int dogs;

如果在extern外部变量后,又声明了同名的变量,则本地使用的为本地声明的变量,加上::作用域解析运算符后则是变量的全局版本。


mutable可以用于指出,结构变量为const的情况下,其成员也可以被修改

1
2
3
4
5
struct data{
char name[20];
mutable int accesses;
}
const data p;


动态存储分配
1.new的初始化

1
2
3
4
5
6
7
//初始化用于单值变量
int *pin=new int {6};
double *pdo=new double {99.99};
//初始化常规结构或数组需要用大括号的列表初始化
struct where {double x,double y,double z};
where *one = new where{2.5,5.3,7.2};
int *ar=new int [4] {2,4,6,7};

new运算符还有一种变体,被称为定位new运算符
要使用这种特性,需要包含new头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<new>
struct chaff{
char dross[20];
int slag;
};
char buffer1[50];
char buffer2[500];
int main(){
chaff *p1,*p2;
int *p3,*p4;
p1=new chaff; //在堆中分配
p3=new int[20]; //在堆中分配
p2=new (buffer1)chaff; //在buffer1中分配
p4=new (buffer2)int [20]; //在buffer2中分配
}
//这段程序就实现了定位分配内存的功能...
//定位new分配的内存不能直接使用delete来释放


名称空间
C++新增了一种功能,即通过定义一种发明的区域来创建命名的名称空间。这样做的目的之一是提供一个声明名称的区域。一个名称空间中的名称不会与另外一个名称空间的相同名称发生冲突,同时允许程序的其他部分使用该名称空间中声明的东西。

1
2
3
4
5
6
7
8
9
10
11
12
namespace Jack{
double pail;
void fetch();
int pal;
struct well{...};
}
namespace Jill{
double bucket(double n){...}
double fetch;
int pal;
struct Hill;
}

1.名称空间可以是全局的,也可以位于另一个名称空间中,但不能代码块中
2.因此,在默认情况下,名称空间中声明的名称的链接性为外部的
3.任何名称空间中的名称都不会与其他名称空间中的名称冲突
4.名称空间是开放的,即可以把名称加入到已有的名称空间中

当然需要一种方法来访问给定名称空间的名称。最简单的方法就是通过作用域解析运算符::,使用名称空间来限定该名称;

1
2
3
Jack::pail=12.34;
Jill::Hill mole;
Jack::fetch();

而如果我们不希望每次使用名称都对它进行限定。using声明使特定的标识符可用,using编译指令使整个名称空间可用。

1
2
using Jill::fetch; //using声明
using namespace Jack; //using编译指令

如果两个名称空间中有相同的成员pal,不能通过using声明限定它们

1
2
3
4
//错误示范
using jack::pal;
using jill::pal;
pal=4; //conflict

同样的,如果某个名称已经在函数中生命了,则不能用using声明导入相同的名称。
如果有局部声明,将隐藏全局变量和名称空间的名称。

局部变量声明后直接用
全局变量如果未有重名局部变量,可直接使用,否则要使用作用域解析运算符
名称空间例如jill::name来用,如果未有全局变量和局部变量重名的声明,在using声明或者using编译指令后可直接使用。

客观来说,使用using声明比使用using编译指令更安全,它只导入指定的名称。

补充,可以将名称空间声明进行嵌套。

1
2
3
4
5
6
7
8
namespace elements{
float water;
namespace fire{
int flame;
..
}
...
}

因此这里的flame就是element::fire::flame.
同样,可以使用下面的usiang编译指令使内部的名称可用

1
using namspace elements::fire;

此外也可以在名称空间中使用using声明和using编译指令

1
2
3
4
5
6
nampspace myth{
using Jill::fetch;
using nampspace elements;
using std::cout;
using std::cin;
}

此后,由于Jill::fetch现在位于名称空间myth,因此要访问fetch

1
std::cin>>myth::fetch;

可以通过省略名称空间的名称来创建未命名的名称空间

1
2
3
4
namespace{
int ice;
int bandycoot;
}

这就像后面跟着using编译指令一样,也就是说在该名称空间中声明的潜在作用域为:从声明点到该声明区域末尾。由于这种名称空间没有名称,因此不能显式地使用using编译指令或using声明来使它在其他位置都可用。具体而言,就是不能在未命名名称空间所属文件之外的其他文件中使用该名称空间中的名称。


名称空间的指导原则

1.使用在已命名的名称空间中声明的变量,而不是使用外部全局变量
2.使用在已命名的名称空间中声明的变量,而不是使用静态全局变量
3.如果开发了一个函数库或类库,将其放在一个名称空间中。
4.不要在头文件中使用using编译指令。因为这样做掩盖了要让哪些名称可用。
5.导入名称时,首选使用作用域解析运算符或using声明的方法。
6.对于using声明,首选将其作用域设置为局部而不是全局。


Thanks for your reward!