一、多文件单独编译:
头文件(.h) | 实现文件(.cpp) | 主程序(.cpp) |
1>函数原型(而非定义)、函数模板原型声明 2>结构、类声明 3>内联函数 | 1>函数、函数模板实现 2>结构、类实现 | 主函数(main()等) |
//使用以下写法防止重复include" " #ifndef ..._H_ //...一般为头文件名的全大写,符号常量 #define ..._H_ ... //头文件内容 #endif | //包含头文件以使用其中的资源 #include<.h> //库文件使用<> #include".h" //用户自定义文件使用"" | //包含头文件以使用其中的资源 #include<.h> //库文件使用<> #include".h" //用户自定义文件使用"" //一般来说不必重复包含 |
二、各种变量及其存储持续性、作用域和链接性:
int main()
{
int a; //自动变量a
register int b; //寄存器变量b。C++11将register关键字完全废弃,目前相当于C++98的auto(而现有的auto被用于自动类型推断)
{
int a; //代码块中的自动变量只在该块中可见,并优先与该块外的同名变量
}
}
自动变量存储持续性为自动,作用域为局部,无链接性。
//自动变量使用栈(stack)中的内存。
②静态变量:
int a; //作用域为全局,链接性为外部(所有文件都可以使用)
static int b; //作用域为全局,链接性为内部(只有该文件可用)
int main()
{
...;
}
void funct()
{
static int c; //作用域为局部,没有链接性(只有该函数能够使用它)
}
//未被初始化的静态变量将被自动初始化为0;
//函数也可使用static声明在标头处,此时函数链接性为内部,只有该文件可以使用该函数;
//静态变量使用静态区的内存,其只能被初始化一次(包括循环或多次调用导致的重复初始化不会奏效),被初始化之后长期存在与静态区,每次调用继承上一次的值。
void funct()
{
static int c = 0;
c++;
}
//像这样的函数第一次被调用时c初始化为0,其后每次调用不再重复c的初始化,而是直接使用静态区中上次的值
三、符号常量及全局变量的跨文件使用
①主程序和实现文件使用头文件中定义的符号常量:
头文件(.h):
const int a=1; //符号常量
实现文件(.cpp):
#include<iostream>
#include".h"
const int d = 1; //定义在实现文件或主程序文件中的符号常量链接性为内部,只有该文件可以使用
...
std::cout<<a; //符号常量只需要包含其所属头文件就可以直接使用
主程序(.cpp):
#include<iostream>
#include".h"
...
int main()
{
...;
std::cout<<a; //符号常量只需包含其所属头文件就可直接使用
}
//符号常量作为一种资源,其链接性实际上是内部的,通过包含头文件,使得每个实现文件都包含该资源。若要改变这种内部链接性为外部,则使用:
extern const int d = 1; //extern声明的符号常量链接性为外部,这意味着不可以重复包含
//实现文件和主程序文件中的static和const声明,链接性虽然都为内部,作用域为局部,但仍有区别:
static int a = 1; //a为静态变量
const int a = 1; //a为符号常量
②实现文件使用主程序或其他实现文件中定义的全局变量:
主程序(.cpp):
int c = 1;
int main()
{
...;
return 0;
}
实现文件(.cpp):
#include<iostream>
...
extern int c;
std::cout<<c; //使用主程序或其他实现文件中定义的全局变量,必须使用extern声明写在标头处,接下来就可直接使用
void show_c()
{
int c = 2;
cout<<c; //c = 2
cout<<::c; //::c = 1,函数内定义了与已被extern声明的全局变量同名的变量时,使用域运算符(::)区分
}
③主程序使用实现文件中定义的全局变量:
实现文件(.cpp):
int b = 1;
主程序(.cpp):
include<iostream>
...//extern int b;
int main()
{
...;
extern int b;
std::cout<<b; //使用实现文件中定义的全局变量,必须使用extern声明,写在标头或主函数内皆可
}
四、命名空间:
①命名空间(namespace)的声明:
namespace NAME
{
...;
...;
}
//命名空间只能在函数外声明。
//命名空间可以嵌套。
②使命名空间中的名称可见:
1>using声明:
using std::cout; //使用std中的cout
2>using编译指令:
using namespace std; //使std中的所有名称都可见
//很明显,using声明对权限的控制更加精确,所以推荐使用using声明。
//二者的细微区别:
#include "stdafx.h"
#include<iostream>
using namespace std;
namespace n1
{
int x = 1;
}
namespace n2
{
int x = 2;
}
int main()
{
//
using n2::x; //using 声明使程序使用n2中的x,更接近声明的行为(不能与声明重复使用,优先级和声明一样)
using namespace n1; //该句不奏效,using编译使n1的内容可用,而不一定要使用(没有则自动寻找,有则以声明的优先)
//
cout << x << endl;
{
int x = 4;
cout << x << "," << n1::x << "," << n2::x << endl;
}
cout << x << endl;
//
system("pause");
return 0;
}
//using声明与声明行为更加接近,因此using声明与声明行为是互相冲突的:
using n2::x;
int x; //不允许
③使用using向已有的命名空间中添加新名称:
namespace elements
{
namespace fire
{
int flame;
}
}
namespace myth
{
using namespace elements; //向myth中添加elements 必须使用using
}
④复杂(嵌套)命名空间的别名:
#include "stdafx.h"
#include<iostream>
namespace elements
{
namespace fire
{
int flame;
}
}
namespace myth
{
using namespace elements; //向myth中添加elements
}
int main()
{
using std::cout;
using std::cin;
namespace MEF = myth::fire; //使用=起别名 MEF简化
using MEF::flame;
flame = 1;
cout << flame;
return 0;
}
//不同于命名空间的声明只能在函数外,命名空间创建别名可以在任何位置进行。
//使用别名可以简化对复杂(嵌套)命名空间中变量的调用;
⑤未命名的命名空间:
namespace
{
int count; //链接性为内部,using该名称后作用域为using的区域
}
//未命名的名称空间由于其内部变量性质与static类似,且作用域控制更加灵活,故可以成为static的替代品。