前言:
C++,作为C语言的升级语言,它自然有着优于C语言本身的语法特性和语言特点,并且在大家以后进入到工程项目开发的时候,C++的很多兼容性要远远优于C语言,但C++相比C语言到底有哪些好处呢?我想仅仅光说C++强于C语言本身是没有说服力的,所以下面让我们看一看从最基本的几个问题出发,C++强于C语言的几个基础方面。
首先让我们先来看C++最基本的第一个代码:
#include<iostream> using namespace std; int main() { cout<<"hello world!"<<endl; return 0; }
然后再让我们看看C语言是如何实现这样的代码的:
#include<stdio.h> int main() { printf("hello world!"); return 0; }
和我们熟知的C语言相比,C++多了很多东西,namespace是什么?iostream是什么?cout是什么?…接下来让我们一个一个来探究这些问题。在接下来的很多情况中,我基本都利用C语言和C++的特点对比来导入C++的知识点,这样更好理解。
1.命名空间 namespace
作为C++的63个关键字之一,我们变从这第一个namespace关键字开始。
我们在C语言书写时有时候会面临这样一个问题:
#include<stdio.h> #include<stdlib.h> int rand=30; int main() { printf("%d\n",rand); return 0; }
乍一看这行代码没有明显错误,但编译器会出现这样的一行报错
rand不明确,这是因为我们的库文件stdlib.h里面也有一个rand函数或者变量之类的东西,而我们在这里又使用了一个rand,计算机编译的时候不知道你调用的是哪个rand,这就产生了错误,所以这便引出了C语言的第一个问题:命名冲突,C语言本身是无法解决命名冲突的问题的,它的主要冲突主要包括与库函数之间的冲突或者在一个长项目中重复变量名字的冲突。这是很烦人的问题,这导致我们创建变量命名的时候不得不谨小慎微,看看是否有冲突问题,利用大小写和各种不同的标识符号区分开。
但C++便为此提供了一个更好的方法:namespace—命名空间
我们可以这样改:
namespace hbw { int rand=30; } #include<stdio.h> #include<stdlib.h> int rand=30; int main() { printf("%d\n",rand); printf("%d\n,hbw::rand); return 0; }
这时,代码就不会报错了,程序运行的结果如下:
我们加上namespace命名空间的效果就是,命名空间内部定义的变量被namespace如同高墙一样围起来,我们接下来的程序再使用相同名字,它会默认指向名字对应的namespace hbw 命名空间之外的变量,这样hbw里面的rand和外面的rand就被一个namespace区分了开来而不会发生命名冲突的问题,倘若我们想访问hb内部的rand,只需要hbw::rand即可,其中::符号为域作用限定符的意思,他就代表我们必须要访问hbw里面的rand而不是其他地方的。而此时变量的属性是不变的。
1.namespace的几点特性:
首先明确写法:
namespace 名字(注意这里不要加分号)
{
在里面写变量或者函数定义都可以
}
特性1:
命名空间内部也存在冲突问题,而我们的命名空间内部是可以通过嵌套命名空间从而解决这个问题的,例如:
namespace hbwpersonal { int q=30; int arr1[10] = { 0 }; namespace Swap { int q=50; int sz = sizeof(hbwpersonal::arr1) / sizeof(hbwpersonal::arr1[0]); void swap(int* x, int* y)//交换函数 { int tmp = *x; *x = *y; *y = tmp; } }
当我们访问q的时候,也会由于两个命名空间里面都有q,我们倘若仅仅是hbwpersonal::q,计算机无法识别,故我们要这样区分:
printf("%d",hbwpersonal::q); printf("%d",hbwpersonal::Swap::q);
这样两个q就不会发生冲突问题,故我们得出结论:
命名空间也是可以不断嵌套的,如同if语句一个道理。
特性2:
对于实践过程中定义和声明分离的问题
对于不同位置命名空间,倘若名字相同,在计算机编译的时候是可以把同名的命名空间自动按照同一个命名空间去合并为一个的命名空间去处理的。
所以,我们对于处理头文件和函数文件分离的情况的时候,我们完全可以将其封装在相同名字的命名空间内部,这样就相当于定义和声明串联在了一起,和之前的C语言的函数定义和声明就没有本质区别了。这样当我们把函数文件和头文件同时发给别人的时候,它就可以不在乎命名冲突直接用命名空间里面的内容即可。
2.namespace命名空间的展开:
就像小的时候我去乡下,看到村子里的农民有时候要装大棚,有的时候又要拆大棚,我们的namespace也是同理,也可以通过展开来开放使用权限,C++语法的很多内容都涉及到权限,包括后面我们要学的引用等知识,这要是为什么C加加支持各种C语言做不到的东西,它对于权限的划分是更加细致的。
using namespace +对应空间的名字,这样我们对应的空间的权限便全部打开了,就不用我们使用::限定这个命名空间里面的变量或者函数等东西了。
当然,盲目的全部打开风险是很大的,而且很多时候在实际工程中我们可能根本用不到命名空间里面的全部元素,所以C++为我们提供了一个可以指定打开的方式:
using +对应空间的名字+里面的元素名称
通过这样的方式,我们便指定只打开我们想要打开的元素,而不是全展开,这样既方便又降低了风险。
当我们using展开后,我们就不用使用对应的::符号才能调用对应的变量了,只需要像往常一样直接写名字即可。
所以让我们回到我们最开始的第一个C++程序:
using namespace std;
现在我们就能理解它的含义了,其中的我们实际上就是展开了名为std的命名空间,std是C++库里面的官方命名空间,很多C++的关键字都包含其中,加上这句话后,我们就能跟C语言一样直接使用这些关键字,而不是std::cin,std::cout…这样麻烦的操作了。
2.C++的输入输出
C语言和C++在程序上最直观的区别是输入和输出,对于即使看不懂代码或者刚学编程的人(我就是这样)来说,C++的cin cout似乎就是C语言对应的scanf和printf,没错,所以接下来让我们讲讲C++的输入和输出。
1.io流:
我们的第一个C++代码有这么一个引用:
#include<iostream>
我们从这个引用中看出两点,1.C++的头文件引用是不用加.h的 2.我们为什么要引用这个iostream呢?
现在让我们来说说什么是iostream:
iostream即io流的头文件,io流就是in out的缩写,从字面意义上来理解就是进行数据流入和数据流出的文件,我们这里姑且先这样理解,你可以把他理解为C语言我们像用printf就要引用头文件#include<stdio.h>,同理**,我们想要进行cin cout的输入输出,这个引用也是必不可少的。**
2.cin cout关键字:
cin为流提取关键字,即输入关键字,相当于scanf但比scanf使用起来更加方便,不过这也导致了cin没法控制精度,但C++兼容C语言,故原来的C语法在C++也是成立的。
cin最大的特点在于可以自动识别类型,输入什么类型,C++的编译器就按照什么类型处理,不用像scanf那样去指定占位符。
cout为流插入关键字,即输出关键字,相当于printf但同理也更加方便,不过同样也没法控制精度,控制精度还需要C语言。
cout的特点也是自动识别类型,识别什么类型就输出什么类型
cin cout一般共同使用,如下:
int a=0; cin>>a; cout<<a<<endl;
注意,在C++语法中,<< >>不再表示位移操作符,而是代表一种指向和流向,cin流向内存,同理cout<<即从内存中再流出去,在C++中换行一般用endl,就和"\n"道理相同。
<< >>符号可以反复使用搭配换行和变量,可以同时输入和输出多个变量。
注意:
注意这个错误,cin不要写endl,就像scanf不要写\n一样。
3.缺省参数
1.概念:
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实
参则采用该形参的缺省值,否则使用指定的实参。
例如下面的例子:
void Func(int a = 0) { cout<<a<<endl; } int main() { Func(); // 没有传参时,使用参数的默认值 Func(10); // 传参时,使用指定的实参 return 0; }
结果为:
第一个结果为:0
第二个结果为:10
我总结为:
没传参就使用参数的默认值,即我们赋给的0,倘若传参了就是用对应的参数值。也就是你没有就用我的,你要是有那就用你的
2.分类
1.全缺省参数:
即所有的参数都有缺省值,因此我们在传参的时候可以什么值也不传,默认缺省值进入函数执行。
如下:
void Func(int a = 10, int b = 20, int c = 30) { cout<<"a = "<<a<<endl; cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl; } Func();
这样写输出的结果就是:10 20 30.
2.半缺省参数:
即部分参数有缺省值,有些参数没有缺省值,我们传参的时候要注意非缺省参数一定要为其赋值,缺省参数则可以不用赋值
如下:
void Func(int a, int b = 10, int c = 20) { cout<<"a = "<<a<<endl; cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl; }
注意缺省参数的几个注意的点:
1. 半缺省参数必须从右往左依次来给出,不能间隔着给
2. 缺省参数不能在函数声明和定义中同时出现
3. 缺省值必须是常量或者全局变量,不能int a=b,这样是不符合语法的
4. C语言不支持(编译器不支持)
这里特别强调一下第一点的理解,为什么缺省参数部分赋缺省值的时候是从右向左赋值的呢?这是因为我们给非缺省的参数传参是从左向右顺序进行的,故我们也会在赋参数的过程中按左到右的顺序赋予值,为了防止非缺省参数和缺省参数在赋值的时候出现混乱,故我们缺省赋值从右向左进行。
第二点的不能同时出现的原因就是倘若声明和定义所给的缺省值不同,编译器不知道应该识别哪个缺省值,这样就会出现错误。