【C++笔记】九、编译、链接和命名空间

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;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DUANDAUNNN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值