从C语言到C++①(第一章_C++入门_上篇)C++学习介绍(命名空间和C++输入输出流)(上):https://developer.aliyun.com/article/1513630
6.2命名空间里的内容
命名空间里的内容,不仅仅可以存放变量,
还可以在里面放函数,结构体,甚至是 类(我们后面会讲)。
还可以在命名空间里放命名空间,(命名空间的嵌套,就是需要用多层:: 没什么用)
#include <stdio.h> namespace N1 { int a = 10; int b = 20; int Add(int x, int y) { return x + y; } } namespace N2 { int c = 0; struct Node { struct Node* next; int val; }; } int main() { int res = N1::Add(N1::a, N1::b); printf("result = %d", res); struct N2::Node node1; return 0; }
6.3命名空间重名问题
命名空间是用来解决命名冲突问题的,
那我项目中定义的某个命名空间的名字和其他命名空间的名字冲突了怎么办?
其实, 在同一个工程中是允许存在多个相同名称的命名空间的。
编译器最后会将他们合成到同一个命名空间中的。
有两个相同名字的命名空间,就会合二为一。有三个相同名字的命名空间,就会三合一……
所以:同一个工程中允许存在多个相同的命名空间,编译器最后会将它们合成到一起。
6.4命名空间展开问题
假设有这样的一种情况,一个命名空间中的某个成员是我们经常要使用的:
#include <stdio.h> namespace N1 { int a = 10; // 假设a经常需要使用 int b = 20; int c = 30; } void func(int n) { printf("HI, %d\n", n); } int main() { printf("%d\n", N1::a); int res = N1::a; func(N1::a); printf("hello, %d\n", N1::a); return 0; }
指定的作用域,能够做到最好的命名隔离,但是使用起来好像不是很方便。
每次使用都要调 : : 这也太难受了,有办法能解决吗?
可以用 using namespace 将整个命名空间展开,因为命名空间是在全局土生土长的,所以展开后,里面的东西自然会被展开到全局
using namespace 空间名;
#include <stdio.h> namespace N1 { int a = 10; // 假设a经常需要使用 int b = 20; int c = 30; } void func(int n) { printf("HI, %d\n", n); } using namespace N1; // 将N1这个命名空间展开 int main() { printf("%d\n", a); // 这样我们就可以直接使用了,就不需要 "::" 了 int res = a; func(a); printf("hello, %d\n", a); return 0; }
6.5匿名命名空间
在C语言学习结构体的时候,就提到过匿名结构体。
命名空间这里也可以匿名。如果一个命名空间没有名称,我们就称它为匿名结构体。
// 匿名命名空间 namespace { char c; int i; double d; }
这种情况,编译器会在内部给这个没有名字的 "匿名命名空间" 生成一个惟一的名字。
并且还会为该匿名命名空间生成一条 using 指令,所以上面的代码会等同于:
namespace _UNIQUE_NAME { char c; int i; double d; } using namespace _UNIQUE_NAME;
这里只需要知道有这么一个东西就可以了。
7.C++的输入与输出
刚才之所以讲解命名空间,就是为了让大家能够慢慢地看懂前面写的 Hello World!
#include <iostream> using namespace std; int main() { cout << "Hello World!" << endl; return 0; }
但是在讲解C++的输入与输出之前,还需要再对命名空间做一个小小的补充。
库也是会用命名空间的,C++库的实现定义包含在了一个叫 std 的命名空间中。
加上 using namespace std ; 是为了把 std 空间中所有的内容都展开,
这样就可以直接使用它们了,前面说过这样实际是不好的,但平时练习时可以这样写。
为什么C++要把它封装到一个叫 std 的命名空间中呢?
因为这样就不容易冲突了,有效放置了冲突命名。
注意事项:这里要提一下,有些老的教材上有 #include <iostream.h>
这个在老的编译器上是可以的,比如 VC6.0 ,比较老的版本的库,没有命名空间。
早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件 即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文 件不带.h;是因为新的c++摈弃了.h形式的头文件。现在是标准c的头文件是.h,标准c++头文件不带.h。旧编译器(vc 6.0)中还支持 <iostream.h> 格式,后续编译器已不支持,因此推荐使用 <iostream> +std 的方式。
7.1 输入和输出
cout 标准输出(控制台)和 cin 标准输入(键盘)时,必须包含 <iostream> 头文件。
并且需要使用 std 标准命名空间,这里会详细探讨。
7.1.1 流插入运算符 <<
cout 后面的 << ,我们称之为 "流插入运算符" 。就像水流的流向一样。
cout 用法演示:
#include <iostream> using namespace std; int main() { cout << "Hello"; // 等同于 printf("Hello"); return 0; }
上面的代码,之所以可以直接用 cout,是因为我们已经把 std 这块库命名空间展开了。
下面会对专门对展开方式进行一个探讨。
此外,如果想换行,可以使用 endl 。它就"相当于" \n,都可以起到一个换行的效果。
大量输入输出时尽量少用或者不用 endl ,每次 endl 会刷新缓冲区,这增加了 io 次数,
在数据非常大的时候尽量不要用endl,转义字符不存在刷新缓冲区的问题。
即 —— 需要大量输入输出时建议用 \n 替换 endl 。
使用 C++ 的输入输出是很方便的,它最大的特点就是可以自动识别类型。
#include <iostream> using namespace std; int main() { int i = 10; double d = 3.14; cout << i << " " << d << endl; // 相当于 printf("%d %f\n", i, d); return 0; }
这就比C语言方便多了。
7.1.2 流提取运算符 >>
cin 后面的 >> ,称之为 "流提取运算符" 。和C语言scanf作用一样,但和上面流插入 << 一样,也是会自动识别类型。
#include <iostream> using namespace std; int main() { int i = 0; double d = 0.0; cout << "请输入一个整数和一个小数: "; cin >> i >> d; cout << "你输入的是: "; cout << i << " 和 " << d << endl; return 0; }
7.2 C和C++的混合使用
前面说过C++是兼容C的,因为 <iostream> 有些平台间接的包了 printf 等 C语言中的函数。
有人这时候就会觉得,C++的输入和输出可以自动识别类型,这也太爽了吧,既然 C++ 的输入输出这么好用,那我们是不是就用不上 C语言里的输入输出了?
不是,举个简单的栗子:
如果我们想打印某个浮点数,如何控制小数点后的位数呢?在 C++ 的输入中,这是一件比较麻烦的事情。如果想控制小数点的位数,我们完全可以使用C语言的输入:printf("%.2f", d);
因此,并不是说学了C++的输入输出,就不用C语言的输入输出了。
C++ 和 C语言的输入输出可以混在一起写,混在一起用。
什么时候用 C++ 的,什么时候用 C语言的,看情况就可以了。
(在后面熟悉C++后还能用C++和C一起打面向过程和面向对象的组合拳)
struct Student { char name[20]; int age; }; int main() { // 这种情况C++ 就不方便了 struct Student s = {"xiaoming", 18}; cout << "姓名:" << s.name << endl; cout << "年龄:" << s.age << endl << endl; // 用c呢? printf("姓名:%s\n 年龄:%d\n", s.name, s.age); // 所以说C语言也是有它的优势的 return 0; }
7.3 再看命名空间的展开
上面我们讨论过使用 using namespace 展开的缺陷,会失去隔离的效果。
这样写好吗?不好。这么一来就全展开来了,所以可以这么写:
采用方式一:空间名 + 作用域限定符
#include <iostream> //using namespace std; int main() { // cout << "hello world!\n" << endl; std::cout << "hello world!" << std::endl; // 指定命名空间 return 0; }
采用方式二:使用 using namespace 命名空间名称引入 (会破坏隔离效果)
#include <iostream> using namespace std; int main() { cout << "hello world!" << endl; return 0; }
虽然 using namespace 会破坏隔离效果,但是我们平时写练习还是可以这么去做的。因为我们平时不需要这么过分地讲究命名空间,但是以后在写项目或干正事的时候就得讲究讲究了。
采用方式三:使用 using 将命名空间中成员引入
#include <iostream> using std::cout; // 把常用的展开 using std::endl; int main() { cout << "hello world!" << endl; return 0; }
8.再看Hello World!
#include <iostream> using namespace std; int main() { cout << "Hello World!" << endl; return 0; }
现在是不是都能明白了?恭喜你学会Hello World!了,正式踏上了C++的学习之路!
学习C++是一个漫长的过程,当然你可以逝逝下面的21天学会C++: