【C++杂货铺】C++介绍、命名空间、输入输出
一、C++前言介绍
1.1 什么是C++?
C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机,20世纪80年代,计算机界提出了OOP(object oriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。1982年,Bjarne Stroustrup博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。因此:C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。
1.2 C++的发展史
1979年,贝尔实验室的本贾尼等人试图分析unix内核的时候,试图将内核模块化,于是在C语言的基础上进行扩展,增加了类的机制,完成了一个可以运行的预处理程序,称之为C with classes。
语言的发展就像是练功打怪升级一样,也是逐步递进,由浅入深的过程。我们先来看下C++的历史版本。
C++还在不断的向后发展。但是:现在社会上主流使用还是C++98和C++11,所有重点要把C++98和C++11掌握好,随着对C++理解不断加深,有时间可以去琢磨下更新的特性。
二、C++关键字
C++一共有63个关键字,如下所示:
三、命名空间
3.1 为什么要有命名空间?
大型程序一般会使用多个独立开发的库,这些库又可能定义大量的全局变量的名字,如类、函数和模板等。当程序用到多个供应商提供的库时,不可避免地会发生某些名字相互冲突地情况。多个库将名字放置在全局命名空间中将引发命名空间污染(namespace pollution)。
为了解决上面的问题,于是提出了命名空间的概念,命名空间分割了全局命名空间,其中每一个命名空间是一个作用域。域是一种空间概念,常见的域有:局部域、全局域、类域、命名空间域,域会影响访问和生命周期。
3.2 命名空间定义
一个命名空间的定义包含两部分:首先是关键字namespace
,随后是命名空间的名字。在命名空间名字后面是一系列由花括号括起来的声明和定义。只要是能出现在全局作用域中的声明就能置于命名空间内,主要包括:类、变量(及其初始化操作)、函数(及其定义)、模板和其他命名空间(这意味着命名空间可以嵌套):
namespace wcy//命名空间的名字
{
//定义变量
int rand = 10;
//定义函数
int Add(int left, int right)
{
return left + right;
}
//定义类型
struct Node
{
struct Node* next;
int val;
};
//嵌套命名空间
namespace N2
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
上面的代码定义了一个名为wcy
的命名空间,该命名空间包含有变量、函数、类型、命名空间。和其他名字一样,命名空间的名字也必须在定义它的作用域内保持唯一,如果在同一个作用域中出现多个相同名字的命名空间,编译器最后会把他们合并,这意味着命名空间可以是不连续的。命名空间既可以定义在全局作用域内,也可以定义在其他命名空间中,但是不能定义在函数或类的内部。
小tips:
命名空间作用域后面无须跟分号。
3.3 每一个命名空间都是一个作用域
和其他作用域类似,命名空间中的每个名字都必须表示该命名空间内的唯一实体。因为不同命名空间的作用域不同,所以在不同命名空间内可以有相同名字的成员。
定义在某个命名空间中的名字可以被该命名空间内的其他成员直接访问,也可以被这些成员内嵌作用域中的任何单位访问。位于该命名空间之外的代码则必须通过域作用限定符::
明确指出所用的名字属于哪个命名空间。
namespace wcy
{
int a = 10;
}
int a = 30;
int main()
{
int a = 20;
printf("%d\n", a);
printf("%d\n", ::a);
printf("%d\n", wcy::a);
return 0;
}
上面的代码在局部域、全局域、wcy命名空间域中分别定义了一个a
变量并且赋了不同的值,在没指定作用域的时候,会根据局部优先的原则去访问局部变量;::a
的左边什么也没有意味着去全局域中查找;wcy::a
则指定了要到wcy
这个域里面去查找。
3.4 命名空间的使用方法
命名空间有以下三种使用方法:
- 加命名空间名称以及作用域限定符
int main()
{
printf("%d\n", wcy::a);
return 0;
}
- 使用using将命名空间中某个成员引入
using wcy::b;
int main()
{
printf("%d\n", wcy::a);
printf("%d\n", b);
return 0;
}
- 使用using namespace 命名空间名称 引入
可以用using namespace wcy
将命名空间展开,把命名空间中的成员提升到包含命名空间本身和using指示
最近的作用域。
namespace wcy
{
int a = 10;
int b = 5;
int c = 100;
}
int a = 30;
using namespace wcy;
int main()
{
printf("%d\n", a);//a不明确,出现二义性
printf("%d\n", ::a);//正确:访问全局的a
printf("%d\n", wcy::a);//正确:访问wcy中的a
printf("%d\n", b);//正确,去访问wcy中的b
int c = 89;//当前局部变量的c隐藏了wcy::c
c++;//当前局部的c设置成90
return 0;
}
以上面的代码为例,通过using
把wcy
命名空间展开,这个过程相当于把wcy
中的名字“添加”到全局作用域中,这使得程序可以直接访问wcy
中的所有名字。
当命名空间被注入到它的外层作用域之后,很可能该命名空间中定义的名字会与其外层作用域中的成员冲突。例如在主函数中,wcy
的成员a
就与全局作用域中的a
产生了冲突。这种冲突是允许存在的,但是要想使用冲突的名字,我们就必须明确指出名字的版本。main
函数中所有未加限定的a
都会产生二义性错误。
为了使用像a
这样的名字,我们必须使用作用域运算符来明确指出所需的版本。我们使用::a
来表示全局作用域中的a
,而使用wcy::a
来表示定义在wcy
中的a
。
因为main的作用域和命名空间的作用域不同,所以main内部的声明可以隐藏命名空间中的某些成员的名字。例如,局部变量c
隐藏了命名空间的成员wcy::c
。在main中使用c
不存在二义性,他指的就是局部变量c。
3.5 嵌套的命名空间
嵌套的命名空间同时是一个嵌套的作用域,它嵌套在外层命名空间的作用域中。嵌套的命名空间中的名字遵循的规则与往常类似:内层命名空间声明的名字将隐藏外层命名空间声明的 同名成员。在嵌套的命名空间中定义的名字只在内层命名空间中有效,外层命名空间的代码想要访问它必须在名字前添加限定符。
namespace wcy
{
int a = 10;
namespace wcy1
{
int a = 900;//将外层作用域的a隐藏了
int d = 1000;
}
//int b = d;//不正确:d是未声明的标识符
int b = wcy1::d;//正确访问的是wcy1里面的d
namespace wcy2
{
int f = wcy1::d;//正确
}
}
int main()
{
printf("%d\n", wcy::wcy2::f);
printf("%d\n", wcy::wcy1::a);
printf("%d\n", wcy::a);
return 0;
}
3.6 C++标准库的命名空间
std
是C++标准库的命名空间,C++将标准库的定义实现都放到这个命名空间中。
std命名空间的使用惯例:
- 在日常练习中,建议直接用
using namespace std
即可,这样很方便。 - 在项目开发中由于代码较多、规模大,就很容易出现冲突问题,所以建议指定命名空间去访问或者使用
using
把常用的名字引入。
四、C++输入和输出
#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{
cout << "Hello C++" << endl;
return 0;
}
代码说明:
- 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含头文件以及按命名空间使用方法使用std。
- cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,它们都包含在头文件中。
<<
是流插入运算符,>>
是流提取运算符。- 使用C++的输入输出更加方便,不需要像printf和scanf输入输出那样,需要手动控制格式。C++的输入输出可以自动识别变量类型(本质上是运算符重载),但cout和cin的效率比较低。
- 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识,这些我将在后面逐一分享给大家。
注意:
早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需要包含了对应的头文件即可,后来将其实现在std
命名空间下,为了和C的头文件区分,也为了正确使用命名空间,规定C++的头文件不带.h。有一些旧编译器中还支持<iostream.h>格式,现在一些新的编译器已不再支持,因此推荐使用<iostream>配合std的方式。
今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,您的支持就是春人前进的动力!
- 点赞
- 收藏
- 关注作者
评论(0)