1.1 标C++秘籍开篇

标C++

背景介绍

image-20250701000257386

image-20250701000607715

C++完美兼容C

用c++编译器编译c代码发现完美通过

#include <stdio.h>
#include <iostream>

int main(void){
    std::cout << "hello world" << std::endl;
    return 0;
}

第一个C++程序

image-20250701001235701

告诉编译器要使用gcc里面的g++来编译这个代码

day01$gcc 01_hello.cpp -o 01_hello -lstdc++

后缀名可以使用c/cpp/cxx/cc,一般使用cpp:

day01$mv 01_hello.cpp 01_hello.cxx
day01$ls
01_hello  01_hello.cxx
day01$01_hello
hello world

初步认识iostream

iostream路径:

image-20250612162530278

观察一下以下三个:

image-20250612170508924

c++库的cstdio包括了c库的stdio.h:

image-20250612171023129

cstdlib和ctring亦然。

名字空间

image-20250701001540220

代码示例:

day01$vi nameconf.cpp
//用来维护工行卡的余额
#include <iostream>
int g_money = 0;
//存
void save(int money){
    g_money += money;
}
//花
void pay(int money){
    g_money -= money;
}

int main(void){
    save(10000);
    pay(3000);
    std::cout << "工行卡余额:" << g_money << std::endl;
    return 0;
}
day01$g++ nameconf.cpp -o nameconf
day01$ls
01_hello  01_hello.cpp  nameconf  nameconf.cpp
day01$nameconf
工行卡余额:7000

现在假设还要维护一张建行卡,把第3行~第9行的代码复制到第9行的下面:

image-20250612174457623

回车后结果如下:

image-20250612175014752

此时会报重定义的错误,不改名字该如何解决呢?

———通过名字空间。namespace就是在全局域和局部域之间又建立了一层作用域

image-20250615200205049

1.名字空间定义
//用来维护工行卡的余额
#include <iostream>
namespace ICBC{
    int g_money = 0;
    //存
    void save(int money){
        g_money += money;
    }
    //花
    void pay(int money){
        g_money -= money;}
}

namespace CCB{
    int g_money = 0;
    //存
    void save(int money){
        g_money += money;
    }
    //花
    void pay(int money){
        g_money -= money;
    }
}

int main(void){
    ICBC::save(10000);
    ICBC::pay(3000);
    std::cout << "工行卡余额:" << ICBC::g_money << std::endl;
    
    CCB::save(10000);
    CCB::pay(7000);
    std::cout << "建行卡余额:" << CCB::g_money << std::endl;
    return 0;
}
day01$g++ nameconf.cpp -o nameconf
day01$./nameconf
工行卡余额:7000
建行卡余额:3000

save和pay现在没有直接暴露在全局域中,不能直接用;但是ICBC和CCB暴露在全局域中,可以直接用。

2.名字空间合并

名字空间是可以拆开来写的(程序员拆开,编译器合并):

image-20250615200843759

3.声明定义分开

CCB为例:

namespace CCB{
    int g_money = 0;
    //存
    void save(int money){// 连 声明 带 定义
        g_money += money;
    }
    //花
    void pay(int money);// 声明
}
void pay(int money){// 定义
    g_money -= money;
}

如果要把声明和定义分开来写的话,一定要让它们保持契合/一致性;
上述CCB代码中声明的pay是名字空间当中的,而第10行的pay也可能是全局变量,它不能体现出是第8行声明过的pay的定义。

可以这么改:

void CCB::pay(int money){// 定义
    g_money -= money;
}

使用名字空间的三种方式:

1.作用域限定符(高可靠):::
2.名字空间指令(低可靠):
day01$cp 02_nameconf.cpp 03_diruse.cpp
day01$vi 03_diruse.cpp
//名字空间指令
#include <iostream>
namespace ns{
    int g_value;
}

int main(void){
    using namespace ns;// 从这行代码开始 ns中的所有内容在 当前作用域 可见
    g_value = 100;
    std::cout << "ns::g_value = " << ns::g_value << std::endl;
    return 0;
}
day01$g++ 03_diruse.cpp -o 03_diruse
day01$./03_diruse
ns::g_value = 100

验证名字空间指令的低可靠:

1.定义一个局部变量g_value

//名字空间指令
#include <iostream>
namespace ns{
    int g_value = 0;
}

int main(void){
    int g_value = 0;
    using namespace ns;// 从这行代码开始 ns中的所有内容在 当前作用域 可见
    g_value = 100;// 5 / 9
    std::cout << "ns::g_value = " << ns::g_value << std::endl;
    return 0;
}

第10行访问的g_value是第4行的还是第9行的?

———第9行

day01$./03_diruse
ns::g_value = 100

编译器在编译每一个函数之前,都会弄两张表,编译器用完了就会销毁,不存到代码里面,编译器拿到标识符先去定义表里找再去可见表里找,若在定义表当中找到了就不找了

image-20250615224441118

2.把局部变量g_value改成全局变量

//名字空间指令
#include <iostream>

namespace ns{
    int g_value = 0;
}
int g_value = 0;
int main(void){
    using namespace ns;// 从这行代码开始 ns中的所有内容在 当前作用域 可见
    g_value = 100;// 5 / 7
    std::cout << "ns::g_value = " << ns::g_value << std::endl;
    return 0;
}

则第10行访问的g_value是第5行的还是第7行的?

———编译器会报错

image-20250616161503082

全局变量不是main函数自己定义的,所以在可见表当中。

3.把using namespace ns;也放到全局域当中同样报错,当前作用域是全局域,编译器不知道访问谁

//名字空间指令
#include <iostream>

namespace ns{
    int g_value = 0;
}
int g_value = 0;
using namespace ns;// 从这行代码开始 ns中的所有内容在 当前作用域 可见
int main(void){
    g_value = 100;// 5 / 7 / err
    std::cout << "ns::g_value = " << ns::g_value << std::endl;
    return 0;
}

image-20250616161503082

最终代码:

//名字空间指令
#include <iostream>
using namespace std;
namespace ns{
    int g_value = 0;
}

int main(void){
    using namespace ns;// 从这行代码开始 ns中的所有内容在 当前作用域 可见
    g_value = 100;
    cout << "ns::g_value = " << ns::g_value << endl;
    return 0;
}
3.名字空间声明(04_impname.cpp)

验证优点:

//名字空间申明
#include <iostream>
using namespace std;
namespace ns{
    int g_value = 0;
}

int main(void){
    using ns::g_value;// 从这行代码开始,ns中的g_value引入当前作用域(相当于定义)
    g_value = 100;
    cout << "ns::g_value = " << ns::g_value << endl;
    return 0;
}
ns:g_value = 100

验证缺点(低可靠):

//名字空间申明
#include <iostream>
using namespace std;
namespace ns{
    int g_value = 0;
}

int main(void){
    int g_value = 0;
    using ns::g_value;// 从这行代码开始,ns中的g_value引入当前作用域(相当于定义)
    g_value = 100;// 5 / 9 / err
    cout << "ns::g_value = " << ns::g_value << endl;
    return 0;
}

结果会报重定义的错误:第9行是在定义,第10行又相当于定义。

练习:

名字空间指令和名字空间声明(dlchide.cpp),体验两者的差别:

vi 05_dlchide.cpp 
//名字空间声明 和 名字看见指令的差别
#include <iostream>
using namespace std;

namespace ns1{
    int g_value = 0;
    int g_other = 0;
}

namespace ns2{
    int g_value = 0;
    int g_other = 0;
}

int main(void){
    using namespace ns1;//名字空间指令,ns1中的内容出现在可见表中,所有内容都出现在可见表
    using ns2::g_value;//名字空间声明,ns2中的g_value出现在定义表,只有g_value出现在定义表

    g_value = 888;//ns2的
    cout << "ns1::g_value = " << ns1::g_value << ",ns2::g_value = " << ns2::g_value << endl;
    
    g_other = 666;//ns1的
    cout << "ns1::g_other = " << ns1::g_other << ",ns2::g_other = " << ns2::g_other << endl;

    return 0;
}
day01$./05_dlchide 
ns1::g_value = 0,ns2::g_value = 888
ns1::g_other = 666,ns2::g_other = 0

解析:

1.g_value 通过 using ns2::g_value; 声明被直接引入当前作用域的定义表(也称为注入点),因此它在当前作用域中可直接访问,无需前缀

2.g_other 没有被显式声明,但由于 using namespace ns1; 指令将 ns1 的整个命名空间内容 引入了当前作用域的可见表(也称为候选项集合),因此 g_other 会被解析为 ns1::g_other。

名字空间嵌套image-20250701001637187

vi 06_netstalias.cpp
//名字空间嵌套
#include <iostream>
using namespace std;

namespace ns1{
    int g_value = 100;
    namespace ns2{
        int g_value = 200;
        namespace ns3{
            int g_value = 300;
            namespace ns4{
                int g_value = 400;

            }
        }
    
    }
}

int main(void){
    namespace ns_four = ns1::ns2::ns3::ns4;//名字空间别名,不是给变量起别名
    //cout << ns1::ns2::ns3::ns4::g_value << endl;
    cout << ns_four::g_value << endl;//可以简化书写 
    return 0;
}

ps: 命名空间 == 名字空间 –>namespace

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值