1、多文件编写

1.1、优点:

使得程序整个结构更加清晰;修改更加简便;多文件直接使用,无须重复声明

1.2、程序分类:

1、头文件:用户定义的数据类型(包含结构声明,函数声明,类声明,名称空间以及#define和const定义的符号常量)。
2、源代码文件:操纵用户定义的数据类型的函数的代码。

1.3、头文件使用:

1、假设我们自己写的头文件:swap.h,我们该如何使用该文件呢?
#include "swap.h"

2、但是我们经常看见下面这种方式:
#include<iostream>

3<>""的区别
<>:在尖括号中,则C++编译器将在存储标准头文件的主机系统的文件系统中查找;
"":在双引号中,则编译器将首先查找当前的工作目录或源代码目录。如果没有在那里找到头文件,则将在标准位置查找;
因此包含自己的头文件时,应使用""而不是<>

1.4、避免多次包含同一个头文件:

避免重复定义:该方法可以忽略第一次包含之外的所有内容。

使用预处理编译指令:
#ifndef _HEADFILE_H_			(避免与程序中其他变量重名)
#define _HEADFILE_H_
......
#endif		//_HEADFILE_H_

2、C++管理数据内存

2.1、存储时长、作用域、链接性:

1、存储时长:数据 保留在内存中的时间长短。
2、作用域:描述了变量、函数在文件的多大范围可见。
3、链接性:描述了变量、函数如何在不同的文件中共享。

三种方式:自动存储、静态存储、动态存储

1、	自动存储:函数内部定义的常规变量,被称为自动变量(局部非static变量)
	一般在所述函数被调用自动产生,函数调用结束时消亡;
	通常存储在栈中;

2、	静态存储:分为全局变量和static变量
	通常放在全局区
(后序更新)

3、	动态存储:使用new分配,存储在堆中;

2.2、自动存储(自动变量或者局部变量):

只在包含它们的函数或代码块可见:无链接性,且没有初始化时,初始值不确定

#include<iostream>
using namespace std;
int main()
{
	int T_temp = 10;					
	{
		int T_temp = 20;					函数块内部隐藏上述旧定义
		cout << T_temp << endl;				输出20
	}
	cout << T_temp << endl;					旧定义可见,输出10
	return 0;
}		

2.3、静态持续变量:

持续变量表明它不是和自动变量一样,随着函数调用结束而结束,它的生命周期由整个程序执行期间。
3种链接性:外部链接、内部连接、无链接性
没有显示初始化时,编译器默认初始值设置成0,同理数组和结构均设置成0。

1、外部链接性:其他文件可访问
2、内部链接性:只能当前文件访问
3、无链接性:当前函数或代码块访问

#include<iostream>
using namespace std;

int T_temp1 = 10;					外部链接性,别的文件需要使用该变量时,只需加上extern
									extern为引用声明,告知编译器该变量定义在别的文件,此文件只是需要使用该变量
static int T_temp2 = 20;			内部链接性

void func()
{
	static int T_temp3 = 30;	 	无链接性
}

int main()
{
	......
	return 0;
}
变量名称 存储时长 作用域 链接性
自动变量 函数执行期间 函数内部 无链接性
静态局部变量 程序执行期间 函数内部
静态全局变量 程序执行期间 当前文件 内部链接
全局变量 程序执行期间 其他文件和当前文件 外部链接

2.4、自动变量和静态持续变量:

1、局部变量隐藏同名全局变量;
2、在函数内部和代码块中可以使用作用域解析运算符::来访问隐藏的全局变量;

文件一:

#include <iostream>
double warming = 0.3;			//全局变量
void update(double dt);
void local();
int main()
{
    using namespace std;
    cout << "Global warming is " << warming << " degrees.\n";
    update(0.1); 
    cout << "Global warming is " << warming << " degrees.\n";
    local(); 
    cout << "Global warming is " << warming << " degrees.\n";
    return 0;
}

文件二:

#include <iostream>
extern double warming;  	//使用extern调用其他文件的全局变量

void update(double dt);
void local();

using std::cout;
void update(double dt)
{
    warming += dt;          //使用全局变量的warming
    cout << "Updating global warming to " << warming;
    cout << " degrees.\n";
}

void local()
{
    double warming = 0.8;   //局部变量warming,隐藏全局变量warming 
    cout << "Local warming = " << warming << " degrees.\n";
    cout << "But global warming = " << ::warming;				作用域解析法::
    cout << " degrees.\n";
}

输出结果:
在这里插入图片描述

2.5、不同文件使用相同名字的全局变量:

首先了解一下:单定义规则:变量只能定义一次

文件一:

#include<iostream>
int values = 10;
int main()
{
	return 0;
}

文件二:

#include<iostream>
int values = 50;		两次定义,违反了单定义规则
void func()
{
	//operation
}

修改方法:在一个文件中定义一个静态外部变量,此时静态外部变量将隐藏常规的全局变量。

文件三:

#include<iostream>
int values = 10;
int main()
{
	......
	return 0;
}

文件四:

#include<iostream>
static int values = 50;		允许,此时该文件隐藏文件三中的values
void func()
{
	//operation
}

2.6、静态局部变量:

1、该变量只在该函数中可用,但函数调用结束后仍存在,因此两次函数调用之间,静态局部变量的值将保持上一次的值;
2、只在第一次函数调用时初始化,后序调用不在初始化;

2.7、函数和链接性:

变量有链接性,那么函数是否也有链接性呢?
这是自然的,在C++中函数的存储时长为:整个程序执行期间;
函数的链接性为默认外部链接,可在不同文件中共享,也可以使用关键字extern(可选非必要),但可以使用static声明函数的链接性为内部的,使之只能在一个文件中使用,和静态全局变量一样,此时可以在其他文件中定义同名的函数。

3、名称空间

3.1、什么是名称空间和为什么需要名称空间?

什么是名称空间?
首先,C++里面的名称是指:变量、函数、结构、类等等。而名称空间就是一块区域,里面放的是各种各样的名称。

为什么需要名称空间?
当项目增大时,不可避免的造成名称冲突,而引入的名称空间就可以更好的控制名称的作用域,不同名称空间的相同名称不会发生冲突。

3.2、名称空间的创建和使用方法

1、可以创建为全局的,也可以创建在名称空间的内部,但是不能在代码块内部创建。

2、名称空间是开发的,即可以把名称加入到已有的名称空间中;(可迭代)
namespace fhl{
	string name;
	int age;
	void func();
}
namespace fhl{
	string address;				往名称空间添加名称
}

3、名称空间的声明和定义可以分开
namespace fhl{
	string name;
	int age;
	void func();
}
namespace fhl{					不允许放在函数或代码块中
	void func()
	{
		......
	}
}

4、使用方法:
	使用作用域解析运算符:::
	fhl::name= "xiaofang";

3.3、using声明和using编译指令

上述要想使用特性名称空间的名称,都需要使用作用域解析运算法,比较麻烦,因此引入using声明和using编译指令。

1using声明:使名称空间下特定的名称可用
namespace fhl{
	string name;
	int age;
	void func();
}
namespace fhl{					不允许放在函数或代码块中
	void func()
	{
		cout << "这是一个namespace测试!" << endl;
	}
}

int main()
{
	using fhl::name;
	using fhl::func;			不需要()
	string name;				名称冲突---------error
	cin >> name;				相当于 cin >> fhl::name;
	func();
	return 0;
}

2using编译指令:在全局声明区域使用using编译指令,使整个名称空间可用;在函数中使用编译指令,只能在该函数可用
namespace fhl{
	string name;
	int age;
	void func();
}
namespace fhl{					不允许放在函数或代码块中
	void func()
	{
		cout << "这是一个namespace测试!" << endl;
	}
}
using namespace fhl;			在全局声明区域使用编译指令,使得全局可用

int main()
{
	cin >> name;				直接使用
	func();
	return 0;
}

3.4、using声明和using编译指令的区别

1using声明:声明了相应的名称,如果某个名称已经在函数中声明啦,则不能使用using声明导入相同的名称
namespace fhl{
	string name;
	int age;
	void func();
}
string name;					全局name
int main()
{
	using fhl::name;			局部
	string name;				和上述局部冲突
	......
	return 0;
}

2using编译指令:近似于大量使用作用域解析运算符,因此名称空间和声明区域有相同的名称,using声明会有冲突,但using编译导入的名称将被局部名称隐藏
namespace fhl{
	string name;
	int age;
	void func();
}
string name;					全局name

int main()
{
	using namespace fhl;		相当于fhl::name
	string name;				隐藏fhl::name和全局name,是单独的局部name
	cin >> ::name;				全局name
	cin >> fhl::name;			fhl::name
	......
	return 0;
}

从上述可以看出使用using编译指令导入的名称,可能被局部名称隐藏掉,而且编译器不会发出警告,因此使用using声明更安全(类似于先声明后使用)。

3.5、名称空间的其他用法

1、名称空间的嵌套
	namespace fhl
	{
		string name;
		namespace wy
		{
			string addr;				使用fhl::wy::addr访问
			int age;
		}
		void func();
	}
	
2、名称空间中使用using声明和using编译指令
	namespace fhl
	{
		using wy::addr;					使用fhl::addr或wy::addr访问
		using namespace yxr;
		int age;
		void func();
	}
	使用using namespace fhl直接导入