大话cpp一个程序实现C到C++的过渡(头文件命名空间以及标准输入输出)

Posted 白龙码~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大话cpp一个程序实现C到C++的过渡(头文件命名空间以及标准输入输出)相关的知识,希望对你有一定的参考价值。


Part I、前言

C++,又名C Plus Plus,是一门集合了C语言语法又增添了新鲜元素的高级编程语言。
Plus,有优势,好处的意思。相信大家在学习C语言时有许多痛苦的地方,不过在C++中,某些痛苦可能会得以缓解。
但是,不要以为C++是一门相较C更加简单的语言。当然,也无需害怕,我们慢慢来。
开始之前推荐一个官方的C++文档查询网站:C++ Reference,相信在大家今后的学习之路上有所需要。【ps:网站是纯英文的,但是使用了相对简单的语法和词汇,相信在百度的帮助下大家都能读懂】


Part II、解剖第一个C++程序

#include <iostream>
using namespace std;
int main()
{
	cout << "Hello World!" << endl;
	return 0;
}

或许大家乍一看这个会比较陌生,我们先切换到C语言模式:

#include <stdio.h>
int main()
{
	printf("Hello World!\\n");
	return 0;
}

现在开始从两段代码的第一行找不同——

1、头文件不同

不同的语言有不同的库想必大家都非常好理解,但是注意,这里还有个不同之处就是:C++官方自带的头文件它没有.h后缀!。

值得一提的是,起初的C++头文件还是带上.h后缀的,但是自从C++标准化之后,标准委员会就规定了,C++的标准库都不带.h后缀,此外,由于C++是包含C的,而C的官方头文件都是带上.h后缀的,因此,C++额外规定,C语言原本的头文件在去掉.h后缀的同时还要加上“c”前缀,比如:
<stdlib.h>变成了<cstdlib>,不过在大多数编译器中,比如博主使用的VS2019,写成stdlib.h还是可以识别的。

但是话说回来,如果我们自己写头文件的话,必须有.h后缀!

2、命名空间

相信大多数C++萌新刚入手这款语言时都会很疑惑:为什么我们在写代码之前,包个头文件之后还要再加上一句using namespace std呢?
存在即为合理,想知道为什么必须有,那不妨试试如果没有它会怎么样。

我们可以看到,程序编译错误了,并且错误信息是:

为什么cout和endl都变成了未声明的标识符了呢?
这里就不得不提一下C++里命名空间的概念。

我们可以试想一下这样的一个情形:假如一个学校有两人同名,他们都叫张伟,但是好在他们一个在1班,一个在2班。那么如果有一天,其中一个张伟被通报批评了,那么广播里会怎么说?张伟因为隔着栅栏买鸡排然后…,那么请问那个无辜的张伟会怎么想?委屈死了对不对。因此广播里应该这么说:高二1班张伟同学,因为隔着栅栏买鸡排然后…
加上一个高二1班的限定,那么我们就能锁定目标了,这里的高二1班就是一个命名空间标识符。

命名空间怎么定义呢?如下所示

namespace class1
{
	char name[] = "张伟";
}
namespace class2
{
	char name[] = "张伟";
}

关键词namespace + 命名空间标识符 + 一对花括号
这,就是我们新建的两个命名空间了。

那我要访问1班的张伟该怎么办呢?

命名空间 + 两个冒号 + 你要访问的东西的名字
如果在C语言中,我们想在一个地方定义两个同名的变量可以吗?

int main()
{
	char name[] = "张伟";
	char name[] = "张伟";
	return 0;
}


显然不可以,因为它们都是处在main函数这个作用域中的局部变量!
但是这种情况就可以:

int main()
{
	char name[] = "张伟";
	{
		char name[] = "张伟";
	}
	return 0;
}

或者是这样:

int main()
{
	char name[] = "张伟";
	if (char name[] = "张伟")
	{
		
	}
	return 0;
}

这里的if可以换成for/while…
为什么这样就可以了呢?因为尽管它们有相同的标识符name,但是它们处在不同的作用域当中。比如,第二个name是仅属于if语句中的,超出这个if作用域,它的生命周期就结束了,不可再被访问。
换句话说,if/while这些它们都自带一个大括号{}【ps:有时候不写只是因为可以省略】,而这些大括号连带着if/while,其实就形成了一个独立的作用域了,我们可以称之为大括号作用域。

类似于这里,命名空间本质上就是开辟了一块独立于外界的大括号作用域,在不同的作用域自然可以定义相同标识符的变量。但是不同的是,命名空间给这些大括号作用域起了一个名字,比如我们之前写的class1,class2。

关于命名空间的补充:

  • 命名空间的成员
    命名空间里不仅可以有一些变量,还可以存在函数以及后期我们要学的类…

  • 双冒号::
    ::是一个域操作符,作用域+域操作符就可以访问这个域中的东西。

  • 命名空间可以嵌套定义
    比如:

namespace class2
{
	namespace team1
	{
		char name[] = "张伟";
	}
}

张伟是高二2班第1组的一员。
而访问他就需要这样写: class2::team1::name

  • 同名的命名空间可以合并
    比如:
namespace n
{
	void foo()
	{
		;
	}
}
namespace n
{
	int x;
}

尽管分开定义,但是它们在编译过后会被编译器合并到同一个命名空间中

此外,我们需要知道的是,C++标准库中的所有变量、函数等等标识符都是定义在std这个命名空间中的,正是由于同名的命名空间可以合并,所以尽管这些标识符定义在不同的头文件中,到最后都可以通过std::来访问。

  • using关键字

正是由于标准库所有的中标识符都是定义在std命名空间的,所以我们才需要写上using namespace std;这句话意味着,我要将std这个命名空间的东西展开,接下来我要使用的标识符如果没有特殊标注,那么都将是std里的。

但是这也带来一个问题,如果将std里的标识符全部展开了,那么如果我们定义一个与std里同名的东西,那就会发生冲突了,比如说:

namespace class1
{
	char name[] = "张伟";
}
namespace class2
{
	char name[] = "张伟";
}
using namespace class1;
using namespace class2;
int main()
{
	std::cout << name;
	return 0;
}

我们将class1和class2两个命名空间都展开了,那么我们再输出name就会出问题:

因为name存在于两个命名空间中,那应该cout class1::name呢还是class2::name呢?这是个未知数,也成功地把编译器搞晕了。

学到这里我们就能知道使用命名空间里成员的方式了:
1、直接用using namespace 把整个命名空间展开
但是这种方法很容易造成不同命名空间里成员间的冲突。
2、使用域操作符::来指明某个标识符所在的命名空间
但是这种方法太麻烦了,如果某个标识符很常用,那每次都要指明它的命名空间了。

于是,C++标准又提供了一个折中的方法:using + 命名空间::标识符
比如:

using std::cout;
using std::endl;
int main()
{
	cout << "Hello World!" << endl;
	return 0;
}

这里相当于,我们仅仅展开了cout和endl两个常用的标识符,造成冲突的几率非常非常小,因此是比较推荐的一个方式。
【补充:对于这种方式,我们无需指明标识符的类型,只需要写出标识符即可,比如:】

namespace n
{
	void foo()
	{
		;
	}
}
using n::foo;

实际我们在工程中也会遇到这样的问题,对于不同人负责的部分,它们可能会存在相同的标识符,因此,命名空间是十分有必要的。

3、标准输入输出

在C语言中,输出我们使用printf函数,输入我们使用scanf函数,而这里我们可以看到,C++的输出使用的是cout加上一个左移操作符<<。它究竟是什么呢?是函数吗?大家需要明确的是,它不是函数,而是一个对象。在一开始的学习中我们不需要作深入的了解,只需要了解它的相关使用即可。

首先是C++里的标准输出:cout以及<<。
cout是定义在标准库iostream里的,因此我们在开头要包含这个头文件,正如我们使用printf要包含stdio.h一样。
与printf最大的不同就是,cout的使用无需指明输出变量的格式化形式。
比如,对于int a = 10;C语言需要这样输出:printf("%d",a);而C++可以直接写成cout << a;也就是说,cout可以直接帮我们推演出a的形式。
但是cout也有一个弊端:有时候非常麻烦。
比如,对于int a = 10, b = 20,
C语言输出可以是:printf("a = %d, b = %d",a,b);
而使用cout就必须写成cout << "a = " << a << "," << "b = " << b;
很明显,使用cout会麻烦很多。那么对于这种情况,由于C++是包含C的,我们完全可以使用printf这种更简便的方式输出。

C++里的标准输入:cin以及>>
对于int a;我们想从控制台读取一个数
对于C语言,可以使用scanf("%d", &a);
而对于C++,我们可以这样写:cin >> a;
二者最大的不同就是:cin无需指明a的格式化输入形式,此外还不需要写取地址符号&。
如果想读取多个数,比如int a, b, c;
那么可以写成:cin >> a >> b >> c;
与scanf相同的是,如果遇到空白符,比如空格、Tab、回车,cin会停止读取。
所以,我们需要在键盘上敲出:1空白符2空白符3空白符,然后就可以对abc分别赋值1、2、3了。
其实C++的输入输出的方式跟C语言差不了太多,大家下去用本地IDE自行摸索一下即可掌握基本的方式。

Part III、第一阶段小结

第一阶段的C++学习到这里就结束了。这些对于大家应该难度不大吧?
如果有问题,可以在评论区指出,也希望大家能给博主一些建议!

ps:【大话cpp】系列还在持续更新,欢迎大家关注,有新文章会第一时间推送!

以上是关于大话cpp一个程序实现C到C++的过渡(头文件命名空间以及标准输入输出)的主要内容,如果未能解决你的问题,请参考以下文章

C++头文件和cpp文件的原理

C++头文件和cpp文件的原理

C++头文件和cpp文件的原理

C++:命名空间——如何在头文件和源文件中正确使用?

C++中的静态全局变量

C++创建一个结构体应该放在.cpp文件中吗?然后调用的时候只要包含这个.cpp文件?