1.#include头文件的原理和规则
main.cpp :
#include <iostream>
// 引用自定义头文件,必须用双引号,引用系统的头文件,可以用尖括号,也可以用双引号
// 用<>只会在系统目录中索引,不会在当前目录索引,双引号则首先在当前目录查找,若找不到,再去系统目录找
#include "fun.h" // 为了调用getPersonName
#include "Header.h" // 若Header.h里面include了fun.h,则fun.h多次调用,若fun.h里面没有防止重复定义的措施,则程序报错,里面的内容重复定义
using namespace std;
int main(int argc, const char * argv[])
{
// 头文件中#ifndef
cout << getPersonName() << endl;
return 0;
}
fun.h :
#ifndef header_cpp_fun_h
#define header_cpp_fun_h
#include <iostream>
using namespace std;
string getPersonName();
#endif
person.cpp :
#include "fun.h" // 是为了使用fun.h中的资源,并不是为了string getPersonName();
string getPersonName()
{
return "Bill";
}
2.解决#include重复定义的问题
#ifndef header_cpp_fun_h // 如果这是第一次引用头文件,那么header_cpp_fun_h未定义,那么执行后面的指令,如果定义过了,则后面的指令全部不执行,直到endif
#define header_cpp_fun_h // 定义宏header_cpp_fun_h,表明这个文件已经被使用过了
#include <iostream>
using namespace std;
string getPersonName();
#endif
3.#include的循环引用问题
main.cpp
#include <iostream>
#include "File1.h"
using namespace std;
int main(int argc, const char * argv[])
{
// 循环引用(include)头文件
cout << getValue() << endl; // 输出 Hello Bill
return 0;
}
File1.h
#ifndef __cycle_include__File1__
#define __cycle_include__File1__
#include <iostream>
#include <sstream>
using namespace std;
string getValue();
string getName();
#endif /* defined(__cycle_include__File1__) */
File2.h
#ifndef cycle_include_File2_h
#define cycle_include_File2_h
#include <iostream>
#include "File1.h"
using namespace std;
struct MyStruct
{
string name = getName();
};
#endif
File1.cpp
#include "File1.h" // 若在File1.h中引用File2.h会报错:造成了循环引用
#include "File2.h" // 两个头文件不能互相引用,会构成循环引用从而报错
string getValue()
{
stringstream ss;
MyStruct myStruct;
ss << "Hello " << myStruct.name;
return ss.str();
}
string getName()
{
return "Bill";
}
4.头文件中建议包含和不建议包含的内容
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
// 头文件中建议包含的内容
// 1. 函数原型
// 2. 使用#define或const定义的常量
// 3. 结构声明
// 4. 类声明
// 5. 模板声明
// 6. 内联函数
// 不建议在头文件中放置的内容
// 1. 函数实现部分,若放置了,则当多个CPP文件引用该头文件时,会链接出错,因为有防止重复定义的宏定义
// 2. 变量声明
return 0;
}
5.定义和声明
main.cpp
#include <iostream>
using namespace std;
extern int value;
int main(int argc, const char * argv[])
{
// 定义和声明
// 同一工程下,C++不允许对一个变量多次定义,跨文件也不行
/*
// 定义
int value1 = 20;
int value2;
// 声明
extern int value1;
extern int value1 = 30; // 声明 + 初始化 = 定义
*/
cout << value << endl; // 50
return 0;
}
test.cpp
int value = 50;
void fun()
{
value = 30;
}
6.链接性为外部和内部的变量
main.cpp
#include <iostream>
using namespace std;
extern int age; // 声明外部变量
static int value = 123; // 内部变量,只能文件内部使用,不能跨文件调用,其他来自外部的同名变量被忽略
int main(int argc, const char * argv[]) {
// 链接性为外部和内部的变量
cout << value << endl; // 123
return 0;
}
test.cpp
int age = 40; // 定义,可以跨文件使用
int value = 100;
7.函数中的静态变量(无链接性的局部变量)
#include <iostream>
using namespace std;
void inc()
{
int value = 0; // 普通局部变量,在函数每次调用时进行定义和初始化
static int value_static = 0; // 静态(无链接性的)局部变量,只在第一次调用时进行定义和初始化
cout << "value = " << ++value << endl;
cout << "value_static = " << ++value_static << endl;
}
int main(int argc, const char * argv[]) {
// 函数中的静态变量
// 无链接性的局部变量
for(int i = 0; i < 5;i++)
{
inc();
}
return 0;
}
Out[]:
value = 1 1 1 1 1
value_static = 1 2 3 4 5
8.mutable说明符(允许设置const结构体变量的成员值)
#include <iostream>
using namespace std;
struct MyStruct
{
mutable int code;
mutable string name;
};
int main(int argc, const char * argv[])
{
// mutable说明符(Specifier)
// static extern
const struct MyStruct myStruct = MyStruct();
myStruct.code = 20; // 尽管结构体定义时用const修饰,但其成员使用了mutable,故成员值可以改变
myStruct.name = "abc"; // 若结构体成员不用mutable修饰,则此句报错
const struct MyStruct *pMyStruct = new MyStruct(); // 结构体指针
pMyStruct->code = 100; // 若结构体成员不用mutable修饰,则此句报错
return 0;
}
9.const对链接性的影响
#include <iostream>
using namespace std;
const int code = 10; // 变成了内部变量,且变量不能修改,不会影响其他cpp中同名变量的定义
int main(int argc, const char * argv[])
{
// const对链接性的影响
return 0;
}
10.函数的链接性
main.cpp
#include <iostream>
using namespace std;
/*extern*/ static void process(int); // 声明,在声明时加static会让函数的作用范围仅限于文件内部,在声明时加上extern表示这是函数声明,当然什么都不加时,默认前面是extern
int main(int argc, const char * argv[]) {
// 函数的链接性
// 全局变量:默认是定义 int value;
// 函数:默认是声明(extern)
process(20); // 40
return 0;
}
/*static*/ void process(int n) // 在声明时加static就好,这里可加可不加
{
cout << n + n << endl;
}
test.cpp
#include <iostream>
using namespace std;
void process(int n)
{
cout << n << endl;
}
11.语言链接性
#include <iostream>
using namespace std;
extern "C" void process(int); // 加上“C”后,会按照C语言的命名规则,查找process函数的符号名_process
int main(int argc, const char * argv[])
{
// 语言链接性(本质上就是指定C++编译器在链接时查找函数实现部分的规则【C或C++】)
/*
编译完成后,会为每一个函数生成一个符号名
C语言:一个函数只对应一个名称,函数名:process(int) 符号名:_process,不支持重载,如果两个函数名称相同,那么一定是同一个函数
C++:一个函数可能对应于多个名称 函数名:process(int) 符号名:_process_i
函数名:process(float, double) 符号名:_process_f_d
extern "C" void process(int); // C必须大写,
extern void process(int); // 默认是C++规则
extern "C++" process(int);
*/
return 0;
}
12.命名空间的定义
#include <iostream>
using namespace std;
int value = 40;
namespace namespace1 {
int value = 10;
void process(int);
}
namespace namespace2 {
int value = 20;
}
//using namespace namespace1;
int main(int argc, const char * argv[]) {
// 定义命名空间
// 命名空间可以是全局的(外部链接性),也可以存在于另外一个命名空间内部(嵌套命名空间)
// 命名空间不能存在于一个块内(block)
// 全局命名空间(global namespace)
//cout << ::value << endl;
cout << namespace1::value << endl; // 10
cout << namespace2::value << endl; // 20
namespace1::process(100); // 100
return 0;
}
namespace namespace1 {
void process(int n)
{
cout << n << endl;
}
}
13.使用using namespace和using引用命名空间中的资源
#include <iostream>
using namespace std;
namespace namespace1 {
int value = 10;
void process(int);
}
namespace namespace2 {
int value = 20;
}
// using namespace namespace1; // 可以写在函数前面
int main(int argc, const char * argv[]) {
//using namespace namespace1; // 可以写在函数内部
using namespace1::value; // 只使用命名空间中单个的资源
using namespace1::process;
cout << value << endl;
process(100);
return 0;
}
namespace namespace1 {
void process(int n)
{
cout << n << endl;
}
}
14.嵌套命名空间
#include <iostream>
using namespace std;
namespace persons {
int code = 1;
namespace teacher
{
int age = 40;
int code = 100;
}
namespace student
{
int age = 15;
int code = 200;
}
}
//using namespace persons; // 可以使用persons里的code
using namespace persons::student;
int main(int argc, const char * argv[])
{
// 嵌套命名空间
cout << code << endl; // 200
cout << persons::teacher::age << endl; // 40
using persons::teacher::code;
cout << code << endl; // 100
return 0;
}
15.匿名命名空间
#include <iostream>
using namespace std;
//static int n = 10;
namespace {
int n = 10;
}
int main(int argc, const char * argv[]) {
// 匿名命名空间
// 1. 不能在其他文件中使用匿名空间中的任何资源
// 2. 匿名命名空间可以代替static,拥有内部链接性
cout << n << endl; // 10 n具有内部链接性
return 0;
}