目录
0.C与C++
1.C++的关键字
2.命名空间
2.1域
2.2C中命名冲突问题
2.3命名空间定义
2.4命名空间使用
2.5命令空间的展开&头文件的展开
3.C++的输入&输出
3.1cout&cin
3.1<<流插入运算符
3.2>>流提取运算符
0.C与C++
C++是在C的基础之上,容纳进去了面向对象编程思想,并增加了许多有用的库,以及编程范式等。熟悉C语言之后,对C++学习有一定的帮助。C++兼容99%的C的语法。Cpulspuls
C++入门:
- 补充C语言语法的不足,以及C++是如何对C语言设计不合理的地方进行优化的,比如:作用域方面、IO方面、函数方面、指针方面、宏方面等。
- 为后续类和对象学习打基础。
- VS中后缀.cpp调用C++的编译器,.c调用C的编译器。
#include<iostream>
using namespace std;
int main()
{
cout << "hello word" << endl;
return 0;
}
1.C++的关键字
C++总计63个关键字。C语言总计32个关键字。
2.命名空间
2.1域
域(计算机词汇)_百度百科 (baidu.com)
- 全局域 || 局部域 || 命名空间域 || 类域
- C语言中同一个域里面不能存在同名变量,不同域可以存在同名变量。
- 就近原则,局部优先。先局部再全局。
#include<stdio.h>
int a = 20;
int a = 50;//“a”: 重定义;多次初始化
int b = 70;//ok
int main()
{
int a = 10;
printf("%d",a);//10 先局部在全局
return 0;
}
一般编译器的搜索原则是就近原则,局部优先。先局部再全局。但是我们现在就是想越过局部域的变量,找全局域的变量呢?
使用域作用限定符 ::
- 域 :: 变量
- 无域作用限定符 :: 先局部在整体
- 有域作用限定符 :: 直接去指定的域里面搜索
- 如果 :: 前是空白,则就是在全局域里面搜索
- 如果 :: 前有指定的域,直接去指定域里面搜索(指定域<<<命名空间域C++小知识)
#include<stdio.h>
int a = 20;
int main()
{
int a = 10;
printf("%d",::a);//20
return 0;
}
一般来说,编译器的搜索原则:
- 不指定域:先当前局部域,再全局域。
- 指定域:如果指定了,直接去指定域搜索。(存在于全局域里面)
- 指定域必须使用域作用限定符。
全局域 生命周期 访问- 局部域 生命周期 访问
- 命名空间域 访问
- 类域
就我理解而言,函数里变量存在于局部域,函数外变量全局域,当我们把函数外的某个变量加上限制(域空间),给全局域里某些变量加上访问权限,使其属于某个指定域。(关键字namespace)。存在于全局的同名变量访问有冲突,可以加上命名空间域对全局的域做分割。
- 你使用自家不需要指定,直接搜索。
- 使用外部。若是野生也可以随意使用。若是隔壁的有访问权限的,则需要指定。
#include<iostream>
//全局域
namespace a1//局部域
{
int a = 20;
}
namespace a2
{
int a = 30;
}
int a = 70;
int main()
{
int a = 10;//局部域
printf("%d\n", a);
printf("%d\n", ::a);
printf("%d\n", a1::a);
printf("%d\n", a2::a);
return 0;
}
2.2C中命名冲突问题
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于【全局作用域】中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
- 冲突1:头文件的函数/库会与程序员自己写的全局变量/函数等命名冲突
- 冲突2:在项目当中,两个程序员在不同的文件中写相同的命名的变量,最后合并到一起时会冲突
- ❗注意:处理全局变量的冲突问题,不包括局部的(局部程序员自己写的时候仔细)
//冲突1
#include<stdio.h>
#include<stdlib.h> //头文件包含了rand()产生随机数的函数
int rand = 20;//全局
int main()
{
printf("%d ", rand);
return 0;
}
//❗编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”
//冲突2---多文件
//test.c
#include<stdio.h>
#include"List.h"
#include"Queue.h"
//❗: error C2011: “Node”:“struct”类型重定义
//List.h
#pragma once
//双向链表
struct Node
{
int val;
struct Node* next;
struct Node* prev;
};
void Init(struct Node* phead);
void Push(struct Node* phead, int x);
//Queue.h
#pragma once
//栈
struct Node
{
int val;
struct Node* next;
};
struct Queue
{
struct Node* head;
struct Node* tail;
};
void Init(struct Node* pq);
void Push(struct Node* pq, int x);
2.3命名空间定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{ }即可,{ }中即为命名空间的成员。
- 命名空间中可以定义变量/函数/类型
- 命名空间可以嵌套
- 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。(最后也是同名变量不能存在同一个域里面>>>命名冲突问题)
注意:一个命名空间定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
namespace tsq
{
//变量
int rand = 10;
//函数
int Add(int left, int right)
{
return left + right;
}
//结构体
struct Node
{
struct Node* next;
int val;
};
}
//命名空间可以嵌套
namespace tsq1
{
int a;
int b;
int Add(int left, int right)
{
return left + right;
}
namespace tsq2
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
//List.h
namespace tsq
{
//变量
int rand = 10;
//函数
int Add(int left, int right)
{
return left + right;
}
//结构体
struct Node
{
struct Node* next;
int val;
};
}
//Queue.h
namespace tsq
{
int rand = 20;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
int val;
struct Node* next;
struct Node* prev;
};
}
//ps:一个工程中的Queue.h和List.h中会被合并成一个,形成命名冲突问题
2.4命名空间使用
命名空间的使用有三种方式:
- 加命名空间名称及作用域限定符(变量/函数/结构体/嵌套等)
- 使用using将命名空间中某个成员引入
- 使用using namespace 命名空间名称 引入
std命名空间的使用惯例:
std是C++标准库的命名空间,如何展开std使用更合理呢?
- 在日常练习中,建议直接using namespace std即可,这样就很方便。
- using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现。所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 +using std::cout展开常用的库对象/类型等方式。
- 加命名空间名称及作用域限定符
#include<stdio.h>
namespace tsq
{
//变量
int rand = 10;
//函数
int Add(int left, int right)
{
return left + right;
}
//结构体
struct Node
{
struct Node* next;
int val;
};
//嵌套
namespace xgd
{
void Push()
{
printf("hello word\n");
}
}
}
int main()
{
//变量
printf("%d\n", tsq::rand);
//函数
int count=tsq::Add(1, 2);
printf("%d\n", count);
//结构体
struct tsq::Node phead;
//嵌套
tsq::xgd::Push();
return 0;
}
- 使用using将命名空间中某个成员引入
如果std这个域的权限全部放开,很大可能造成命名冲突问题,
但是又想频繁使用cout和endl这两个对象,一直带std::很不方便,为了方便,我们可以指定放开某个域里面某个变量的权限。
#include<iostream>
//cin 和 cout都属于std的IO流
using std::cout;
using std::endl;
int main()
{
int i = 0;
std::cin >> i;//只用1次
cout << "hello word" << endl;//频繁使用
cout << "hello word" << endl;
cout << "hello word" << endl;
cout << "hello word" << endl;
cout << "hello word" << endl;
cout << "hello word" << endl;
}
- 使用using namespace 命名空间名称引入(做项目不用,练习用,慎用)
#include<iostream>
using namespace std;//直接把这个域的权限全部放开
int main()
{
cout << "hello word" << endl;//存在std这个指定域
cout << "hello word" << endl;
cout << "hello word" << endl;
cout << "hello word" << endl;
cout << "hello word" << endl;
cout << "hello word" << endl;
}
2.5命令空间的展开&头文件的展开
- 头文件的展开:是程序预处理阶段,头文件拷贝一份到当前代码程序中。
- 命名空间的展开:是指把指定某个命名空间域的权限相对于全局域的权限放开,可以像访问全局域一样访问命名空间域。
- 二者不可混为一谈
3.C++的输入&输出
3.1cout&cin
新生婴儿会以自己独特的方式向这个崭新的世界打招呼,C++刚出来后,也算是一个新事物,那C++是否也应该向这个美好的世界来声问候呢?我们来看下C++是如何来实现问候的。
#include<iostream>
using namespace std;
int main()
{
char a[10] = { 0 };
cin >> a;
cout << "Hello world!!!" << endl;
return 0;
}
- C++大多数头文件都是不带.h的后缀(在VC6.0版本中<iostream.h>)
- std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
- cout和cin都是std命名空间域的对象,也包含在<iostream>标准库中。
- 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。
- cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含<iostream >头文件中。
- cout:console控制台
- <<是流插入运算符,>>是流提取运算符。
- 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。
C++的输入输出可以自动识别变量类型。- 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识,这些知识我们我们后续才会学习,所以我们这里只是简单学习他们的使用。后面我们更深入的学习IO流用法及原理。
注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文件不带.h;旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用<iostream>+std的方式。
3.1<<流插入运算符
<<流插入运算符
- <<复用,两种用法。左移,流插入。
- <<流连续插入。
- 类比printf的用法,但是<<可以自动识别类型。
- endl类似'\n'的用法,换行符。end line
- printf为什么不包含#include<stdio.h> <iostream>间接包含了(VS编译器,有些编译器可能没有)
- cout - C++ Reference (cplusplus.com)
#include<iostream>
using namespace std;
int main()
{
//1.左移
int i = 100;
i = i << 1;
const char* str = "hello word";
char ch = '\n';
//2流插入
printf("%d%s%c", i, str, ch);
cout << i << str << ch;
cout << i << str << endl;
return 0;
}
3.2>>流提取运算符
>>流提取运算符
- >>复用,两种用法。右移,流提取。
- >>流连续插入。
- 类比scanf的用法,但是>>可以自动识别类型。
- scanf为什么不包含#include<stdio.h> <iostream>间接包含了(VS编译器,有些编译器可能没有)
- cin - C++ Reference (cplusplus.com)
#include<iostream>
using namespace std;
int main()
{
//1.左移
int i = 100;
i = i >> 1;
//2流提取
int a = 0;
char ch;
char str[10] = { 0 };
cin >> a >> str>>ch;
scanf("%d%s%c", &a,&str,&ch);
return 0;
}
ps:关于cout和cin还有很多更复杂的用法,比如控制浮点数输出精度,控制整形输出进制格等。因为C++兼容C语言的用法,这些又用得不是很多,我们这里就不展开学习了。后续如果有需要,我们再配合文档学习。
🙂感谢大家的阅读,若有错误和不足,欢迎指正。