C++相比C的变化
- 兼容C
- 面向对象
- 泛型
- C的不足的弥补
为什么要有命名空间
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的
#include <stdio.h>
#include <stdlib.h>
int rand = 0;
int main()
{
printf("hello world\n");
printf("%d\n", rand);
return 0;
}
如果有这样一段代码,当不包含stdlib头文件的时候,可以正常运行
但是包含上之后,会显示
命名冲突:全局变量rand和库里面的函数rand冲突了
C的一大缺陷是无法解决命名冲突的问题
场景:
- 定义的名字跟库冲突
- 程序员互相之间会冲突
命名空间的定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。
1. 正常定义一个命名空间
#include <stdio.h>
#include <stdlib.h>
namespace cho
{
int rand = 0;
}
int main()
{
printf("hello world\n");
printf("%d\n", rand);
return 0;
}
这样就可以编译通过
用一堵围墙将定义的全局变量rand围起来,默认不会到墙里面去找
访问rand的时候,默认访问是没有被围起来的rand
会有一个警告
因为全局的rand是一个函数名,也就是一个函数指针
使用%p打印解决问题,打印的就是rand函数的地址
2. 嵌套定义命名空间
如果命名空间里自己定义的名字和自己冲突了
#include <stdio.h>
#include <stdlib.h>
namespace cho
{
namespace cho1
{
int rand = 0;
}
namespace cho2
{
int Add(int left, int right)
{
return left + right;
}
}
struct Node
{
struct Node* next;
int val;
};
}
访问的时候也是嵌套访问
int main()
{
printf("hello world\n");
printf("%d\n", cho::cho1::rand);
cho::cho2::Add(1, 2);
struct bit::Node node;
return 0;
}
命名空间的使用
1. 指定命名空间访问变量
::
域作用限定符
#include <stdio.h>
#include <stdlib.h>
namespace cho
{
int rand = 0;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
int main()
{
printf("hello world\n");
printf("%d\n", cho::rand);
cho::Add(1, 2);
struct bit::Node node;
return 0;
}
cho::rand
:表示访问的是命名空间里的那一个rand,可以访问cho这个命名空间域
函数和结构体同理
2. 展开命名空间访问变量
自己做测试的时候,每次访问变量都要指定命名空间,很麻烦
#include <Stack.h>
using namespace cho;
using namespace std;
int main()
{
ST s;
StackInit(&s);
StackPush(&s, 1);
return 0;
}
展开命名空间,把墙拆了
默认也会在cho这个命名空间搜索
展开了一般就不指定了
using namespace std;
展开std命名空间,std是C++官方库定义的命名空间
C++库里面的东西都在std命名空间里面
在工程项目里面不要这样展开,容易冲突
日常练习,为了方便可以展开
展开了多个命名空间,编译器哪个命名空间都会进
会先去全局里面找ST,全局没有会挨着去找,cho里面找到了就不会再找了
cho没有找到会去std里面去找
如果都没有找到会报错
3. 指定展开命名空间访问变量
每次指定命名空间很不方便
直接展开,全部暴露,又有冲突危险
using std::cout;
using std::endl;
int main()
{
cout << "hello world\n";
int a = 10;
double b = 11.11;
cout << a << endl;
cout << b << endl;
cout << a << endl << b << endl;
return 0;
}
命名空间实际应用
栈
#pragma once
include <stdio.h>
namaspace cho
{
typedef struct Stack
{
int* a;
int top;
int capacity;
}ST;
void StackInit (ST* ps);
void StackPush (ST* ps, int x);
}
#include "Stack.h"
namespace cho
{
void StackInit (ST* ps)
{
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
void StackPush(ST* ps, int x)
{
//...
}
}
多个文件的多个位置的同一个命名空间,编译器会把它们合并成一个
#include <Stack.h>
int main()
{
cho::ST s;
cho::StackInit(&s);
cho::StackPush(&s, 1);
return 0;
}
IO流的基本使用
#include <iostream>
int main()
{
std::cout << "hello world\n";
int a = 10;
double b = 11.11;
std::cout << a << "\n";
std::cout << b << "\n";
std::cout << a << "\n" << b << "\n";
return 0;
}
<<
:流插入运算符
cout在std命名空间里,只有指定了命名空间才可以使用
c - console 暂时理解为控制台/终端
cout可以自动识别输出变量的类型
std::cout << a << std::endl << b << std::endl;
endl
:换行符
>>
:流提取运算符
同样可以自动识别类型
cin >> a >> b;
说明
- 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件
以及按命名空间使用方法使用std。 - cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含
<iostream>
头文件中。 - <<是流插入运算符,>>是流提取运算符。
- 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。
- 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识