IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 2021-07-12:C++基础知识01 -> 正文阅读

[C++知识库]2021-07-12:C++基础知识01

C++基础知识01

Section01:双冒号运算符与作用域

Subsection-1.1:作用域

在C/C++的作用域中,讲究一个就近原则。也就是说,在局部和全局都对某个变量进行了定义时,我们的访问/调用会去操作 “最近” 的那个变量!例如下面的例子:

#include <iostream>

using std::cout;
using std::endl;

int atk = 200;

void test() {
    int atk = 100;
    cout << "Local atk = " << atk << endl;
}

int main() {
    test();
    return 0;
}

大家可以先猜一下运行的结果?没错,就是100!这就是体现了刚刚提到的 “就近原则”。那么,如果在这种情况下,我们还是想要去读甚至写全局的变量atk呢?怎么办呢?看看下面的程序:

#include <iostream>

using std::cout;
using std::endl;

int atk = 200;

void test() {
    int atk = 100;
    cout << "Local atk = " << atk << endl;
    cout << "Global at = " << ::atk << endl;
    ::atk = 800;
    cout << "Global at = " << ::atk << endl;
}

int main() {
    test();
    return 0;
}

然后再看一下运行效果:

在这里插入图片描述
这就是双冒号运算符,改变作用域的效果。在没有指定命名空间的时候,作用域就是全局作用域!

Subsection-1.2:双冒号运算符使用命名空间

所谓命名空间,是管理命名列表而生的。之所以需要对命名进行管理,那是为了在 “迭代开发” 或者是多人 “合作开发” 中,避免 “命名冲突” 的危害!

如何调用命名空间的变量和函数呢?那就是用双冒号作用域限定符!看一个需求:假设在游戏开发中,先开发了英雄露娜的操作,例如:攻击、大招;随后又开发了英雄澜的操作,其中也有攻击和大招,请问怎么实现比较好呢?给出示例程序:

(1)先看看开发Lunar的过程

头文件(实现定义,注意定义就要在命名空间里定义):

#pragma once
#ifndef __LUNAR__
#define __LUNAR__

#include <iostream>
using namespace std;

namespace lunar {
	void goAtk();

	void goUltimate();
}

#endif

CPP文件(负责实现):

#include "Lunar.h"

void lunar::goAtk() {
	cout << "Lunar 释放攻击!" << endl;
}

void lunar::goUltimate() {
	cout << "Lunar 释放大招!" << endl;
}

(2)随后开发Lan的过程

头文件:

#pragma once
#ifndef __LAN__
#define __LAN__

#include <iostream>
using namespace std;

namespace lan {
	void goAtk();

	void goUltimate();
}

#endif

CPP文件:

#include "Lan.h"

void lan::goAtk() {
	cout << "Lan 释放攻击!" << endl;
}

void lan::goUltimate() {
	cout << "Lan 释放大招!" << endl;
}

总结命名空间:

命名空间可以存放C++任何名称,例如变量、结构体、类、函数等等……,并且,命名空间无需加分号!但是命名空间必须放到全局作用域!不可以写入任何一个函数、类!

举一个更简单的例子,要访问两个命名空间的变量和函数:

#include <iostream>

using std::cout;
using std::endl;

namespace ns1 {
    int a;

    void func(int a) {
        cout << a << endl;
    }
}

namespace ns2 {
    int a;

    void func(int a) {
        cout << a << endl;
    }
}

int main() {
    ns1::a = 100;
    ns2::a = 200;
    ns1::func(ns2::a);
    ns2::func(ns1::a);
    return 0;
}

它输出的结果,就显而易见了,是:

200
100

Subsection-1.3:命名空间的编程技法总结

在上面,我们了解了,命名空间的设计目的、设计场景。以及以游戏的迭代开发来了解命名空间的使用!以及简单的例子,了解到命名空间可以加入任意C++中的名称元素(变量、函数、类、结构体等……)。但是,命名空间还是其他的一些有用的技法:

技法1:可扩充的命名空间

以游戏开发为例,澜这个英雄之前有普通攻击、放大招的功能,现在要更新一个回城的功能。而此前的代码不想改动了,可否扩充命名空间呢?如下:

新的的头文件:

#pragma once
#ifndef __LAN__
#define __LAN__

#include <iostream>
using namespace std;

namespace lan {
	void goAtk();

	void goUltimate();
}

namespace lan {
	void goHome();
}

#endif

新的CPP文件:

#include "Lan.h"

void lan::goAtk() {
	cout << "Lan 释放攻击!" << endl;
}

void lan::goUltimate() {
	cout << "Lan 释放大招!" << endl;
}

void lan::goHome() {
	cout << "Lan 回城!" << endl;
}

测试程序:

#include "Lan.h"

int main() {
	lan::goAtk();
	lan::goUltimate();
	lan::goHome();
	return 0;
}

运行后的结果:
在这里插入图片描述
总结:
命名空间可以扩展,每次扩展不是覆盖原有的命名空间,而是把旧的命名空间和新的命名空间合并!

技法2:可匿名的命名空间

这个技法其实没啥大用,就怕有的程序员使用了,而你不知道,就会踩坑!

如果命名空间写为:

namespace {
	int a, b;
}

实际上等价于在当前文件,写了:

static int a;
static int b;

就完全等价于静态变量/函数,意味着只能在当前文件里使用了!比如下面的程序:

#include <iostream>
using namespace std;

namespace {
	void sayHello() {
		cout << "Hello World" << endl;
	}
}

int main() {
	sayHello();
	return 0;
}

运行的结果是:
在这里插入图片描述

技法3:可嵌套的命名空间

命名空间是可以嵌套的!这一般得是很大的项目了!否则,其实命名空间本身也是一个比较大,个人认为是 “仅次于全局作用域” 的存在了!例如:

#include <iostream>
using namespace std;

namespace ns1 {
	int a = 1;

	namespace ns2 {
		int a = 2;
	}
}

int main() {
	cout << ns1::a << ' ' << ns1::ns2::a << endl;
	return 0;
}

运行的结果是:

在这里插入图片描述

技法4:存在别名的命名空间

这个其实很简单,只需要用一个新的namespace空间名去赋值一个旧的命名空间即可,例如:

#include <iostream>
using namespace std;

namespace ns1 {
	int a = 1;

	namespace ns2 {
		int a = 2;
	}
}

int main() {

	namespace newNS = ns1;

	cout << newNS::a << ' ' << ns1::ns2::a << endl;
	return 0;
}

然后输出的结果,和上一个技法的例子,输出一致!

Section02:using关键字用法

Subsection-2.1:用using定义类型别名

对比C语言的 #define 以及 typedef

如果用 #define,则,其规则是:

#define 别名 所代表的名称

如果用 typedef,则,其规则是:

typedef 所代表的名称 别名

例如,分别用 #define 和 typedef 来重命名 unsigned int 和 long long,示例如下:

#include <iostream>

#define uInt unsigned int

typedef long long ll;

int main() {
    uInt u = 102u;
    std::cout << u << std::endl;

    ll l = 999999999999;
    std::cout << l << std::endl;
    return 0;
}

输出的结果是:

102
999999999999

C++11中,用using定义类型别名

如果用using来声明类型别名,则,其规则是:

using 别名 = 所代表的名称;

举个例子:

#include <iostream>

using uInt = unsigned int;
using ll   = long long ;

int main() {
    uInt u = 102u;
    std::cout << u << std::endl;

    ll l = 999999999999;
    std::cout << l << std::endl;
    return 0;
}

其输出的结果,和上面的一致,都是:

102
999999999999

Subsection-2.2:用using进行声明

用using可以用来声明变量和函数,先看一个简单程序:

#include <iostream>

int a = 10;

namespace ns {
    int a = 20;
}

void test() {
    int a = 30;
    std::cout << a << std::endl;
}

int main() {
    test();
    return 0;
}

其输出结果是:

30

这是由于就近原则,不再解释了~

然后,如果想要使用命名空间 ns 的变量 a 呢?可以有这种做法:

#include <iostream>

int a = 10;

namespace ns {
    int a = 20;
}

void test() {
    int a = 30;
    using ns::a;
    std::cout << a << std::endl;
}

int main() {
    test();
    return 0;
}

但是这样会带来报错:

在这里插入图片描述
原因很重要:

using 进行声明的时候,会产生二义性!意味着会和当前作用域其他同名变量发送冲突!换句话说,using的声明和普通的声明,优先级一致!此时,编译器就不知道你到底是要访问谁了?!

Subsection-2.2:用using编译指令

听起来很高级,其实就是为编译器补充了一个需要编译的块,这个块可以理解成一个盒子,盒子里包装这一个命名空间的全部内容!比如:

#include <iostream>

int a = 10;

namespace ns {
    int a = 20;
}

void test() {
    int a = 30;
    using namespace ns;
    std::cout << ns::a << std::endl;
}

int main() {
    test();
    return 0;
}

此时的输出结果,是:

20

需要注意的是:

编译了命名空间,只是让编译器对命名空间的内容完成编译,而其优先级是 低于 当前作用域的声明的!于是,还是会进行就近原则!但是,我们为了能够输出命名空间的变量,就和咱们本文最开始讲的那样,显式调用命名空间的变量!其中关键的程序是:

	using namespace ns;
    std::cout << ns::a << std::endl;

Subsection-2.3:总结using的用法

  1. 在C++11里,可以用来给类型做别名
  2. 可以进行声明,但是要注意二义性,因为其和当前作用域的声明级别一样
  3. 可以编译指令,相当于告诉编译器需要编译命名空间的内容!级别低于当前作用域的声明,如果需要调用命名空间,需要用作用域限定符!
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-13 17:16:52  更:2021-07-13 17:16:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/28 5:46:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码