❀❀❀ 文章由@不准备秃的大伟原创 ❀❀❀
♪♪♪ 若有转载,请联系博主哦~ ♪♪♪
❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤
哈喽大家好哇~真的是好~~~久不见呐,哎呀,不知道有没有铁汁想大伟了?(^▽^ ) 大伟前两周也是忙的很呐,不仅要应付学校的课,还要为了自己的精进也是努力的在学C++啊。大家都说完事开头难,所以大伟为了学好C++也是费了不少功夫,目的也是为了给大家带来更好的博客哈~
那废话不多说,我们正式开始我们的C++的第一节课的学习!鼓掌,啪叽啪叽~
大家回忆一下:我们学C语言一开始是怎么学的? 没错,是一个一个的知识点开始慢慢往上增进的。现在考大家一个基本的问题:C语言有多少个关键字?
哈哈,肯定有很多铁汁不记得是吧,大伟这里直接给出答案:32个,大家要记住哦~ 那既然C++敢叫 C加加,关键字是不是也是加加,那当然是啦,我们C++有63个关键字哦,大家来来看看吧:
这些关键字也不是要大家全记住,以后我们学到再细说,这里先略微的看一看。
OK,接下来我们要提到的是C++补的C语言的第一个坑:
一.命名空间
那命名空间是什么呢?简单来说,就是可以把变量,函数,结构体等等打包在一个空间里面,实现了对这些内容的保护,外部如果想访问其中的成员,则需获取空间的权限,此外,还可以在不同的空间定义相同的成员名字。而这些,是C语言无法实现的。下面给大家上个例子,看看有没有聪明的铁汁发现问题所在:
通过rand下方的红色波浪号可以粗略的了解到这段看似简单而又没有错误的代码有问题,那么这个问题是什么呢?这个时候肯定就有很多铁汁抓破了头也想不明白了。哈哈,大伟在这里也就不为难大家了,直接给出答案:
编译器说rand不明确,但是我们确确实实定义了一个全局变量rand啊,对吧。诶,不知道大家还记不记得我们C语言库有个内置的函数rand,用来得到随机数的。对,我们自己定义的rand变量与库里面的rand函数冲突了,是不是感觉蛮神奇的。
而我们的本贾明博士当时也肯定是遇到了类似的问题,然后再C++中发明出了命名空间这个东西,那我们接下来看看命名空间的定义吧:
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{} 中即为命名空间的成员。
下面简单给大家举个例子:
namespace DaWei
{
//命名空间中可以定义变量/函数/结构体 等等等等
int rand = 0;
int Add(int left, int right)
{
return left + right;
}
struct Node {
struct Node* next;
int val;
};
}
此外,命名空间也可以嵌套,但是:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。案例如下:
namespace DaWei1
{
int rand = 0;
int Add(int left, int right)
{
return left + right;
}
struct Node {
struct Node* next;
int val;
};
namespace DaWei2
{
//被嵌套在里面的命名空间的内容可以和外部命名空间成员有相同的名字或者功能
int rand = 0;
int Add(int left, int right)
{
return left + right;
}
struct Node {
struct Node* next;
int val;
};
}
}
那么我们定义了几个命名空间,但是我们该如何去用空间里的内容呢?当然,简单的用肯定是不行的啦。为了调用命名空间里面的成员,我们需要获得空间的许可,那该如何获得空间的许可呢?我们一般有三种方法:
一.加命名空间名称及作用域限定符
//每次使用的时候展开空间成员
int main()
{
printf("%d\n", DaWei1::a);
//printf("%d", a); 这个会编译报错
return 0;
}
二.使用using将命名空间中某个成员引入
//展开命名空间里面的某个成员
using DaWei1::a;
int main()
{
printf("%d", a);
return 0;
}
三.使用using namespace 命名空间名称 引入
//将整个命名空间展开
using namespace DaWei1;
int main()
{
printf("%d", a);
return 0;
}
OK,到这里命名空间也是大概讲完了,大伟简单给大家复习一下:C++多了命名空间这个概念,目的是保护某些成员,避免与库或者有与相同名字的发生冲突,而我们使用命名空间里的成员时,则需要进行成员展开,一共有三种展开方式,需求不同方法不同。
好,那我们继续马不停蹄的学习下一个知识点:
二.C++特有的输入和输出。
大家在学C语言的时候写的第一段代码基本都是:
int main()
{
printf("hello world!\n");
return 0;
}
是吧,那我们C++作为一款新的语言,是不是也有新的对世界打招呼的方式呢?答案是肯定的,那我们来看看C++是如何实现输出的:
int main()
{
cout<<"hello world!"<<endl;
return 0;
}
其实这么写大家可能会比较奇怪:“C语言的printf 和 scanf不是挺好用的吗,C++要有自己的输入输出,好在哪里?” 诶,先别急,来看一看下面这一段代码:
简单说明一下: cin类似scanf,cout类似printf,endl类似 \n ,那我们再和C语言的代码对比一下(因为代码比较简单,大伟这里就不写了):我们就会发现C++的输入输出的一个巨大的好处,也可以说是便利我们码农的一点:我们在输入输出的时候不需要指定变量的名字了,因为C++他会自动识别。
说明:
1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件 以及按命名空间使用方法使用std。
2. cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
3. < 是流输出运算符,> 是流提取运算符(这个以后会详细讲到,目前大家先记住)。
4. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。 C++的输入输出可以自动识别变量类型。
5. 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识, 这些知识我们我们后续才会学习,所以我们这里只是简单学习他们的使用。后面我们还有有 一个章节更深入的学习IO流用法及原理。
// ps:关于cout和cin还有很多更复杂的用法,比如控制浮点数输出精度,控制整形输出进制格式等 等。因为C++兼容C语言的用法,这些又用得不是很多,我们这里就不展开学习了。后续如果有需要,我 们再配合文档学习。
这里大伟简单说一句有关头文件std的展开:
std是C++标准库的命名空间,如何展开std使用更合理呢?
1. 在日常练习中,建议直接using namespace std即可,这样就很方便。
2. using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对 象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模 大,就很容易出现。所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 + using std::cout展开常用的库对象/类型等方式
ok,C++特有的流输入输出也是到此为止了,总结一下:C++中cin 加 >> 输入,cout 加 << 输出,且两个都不需要声明类型。这两个大伟希望大家私下都练一练,毕竟是C++入门的第一段代码,先要向C++的世界问好才行,是吧?o(*≧▽≦)ツ
三.缺省参数:
缺省参数也是我们C++补的C语言的一个坑,本贾明在写函数的时候,每次调用函数都要传参数进去,但是有些情况一开始不知道要传什么值进去好,但是又不得不调用这个函数。本贾明博士也是很头疼,于是他发明了缺省参数。那我们的缺省参数是什么呢?根据我上面的描述,肯定又聪明的铁汁想到了:缺省参数就是在调用函数的时候可以不传参进去,而是用一开始设计好的一些数据。 而缺省参数也分为以下两种:
全缺省参数:
void func(int a = 10, int b = 4,int c = 200)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
我们在调用函数的时候可以这么做:
由图可得,全缺省参数我们可以不传参数,可以传部分参数,也可以全传。
好,除了全缺省参数外,我们还有半缺省参数,人如其名,只有部分参数给了缺省值:
void func(int a, int b = 4,int c = 200)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
同样,我们调用的时候没有缺省值的就必须要自己传参过去,有缺省值的可以传可以不传,看需求。
注意:
1.半缺省参数和全缺省参数参数都必须从左往右依次给,不能间着
func(5);//合法
func( , , 5);//不合法
func( , 1);//不合法
2.缺省参数不能再函数声明和定义中同时出现,我们一般在定义的时候给。为了防止声明与定义同时出现,而两个位置提供的值不同,那么编译器就无法确定用哪个缺省值。
3.缺省值必须是常量或者全局变量
4.C语言不支持(编译器不支持)
OK,那我们的缺省参数也就学完了,大伟总结一下:缺省参数就是在函数定义的时候给参数的一些初始值,在调用函数的时候可以传参,也可以不传参,但是前提是要有缺省值,且传参的时候不能跳着传。
函数重载:
我们知道,在C语言中不允许同名函数的存在,比如当我们写两个数的相加的时候,我们可能会有整数加整数,浮点数加浮点数,整数加浮点数等等,这样的话我们就需要好几个不同的函数来实现这个大部分代码都相同的函数,而且在调用的时候经常会调用错。老本也是苦于C语言这个特性啊,所以发明了函数重载。
那么函数重载是个什么东西呢?简单来说,就是允许同名函数的存在,而函数的参数不同。简单写个例子:
// 1、参数类型不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
// 2、参数个数不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
以上三点就是支持重载函数存在的条件,不过各位铁汁们注意,函数参数相同而返回类型不同是不构成函数重载的哦~
OK,各位铁汁们,我们的函数重载到这里也就学完了,大伟带大家来回顾一下:C++支持函数重载,条件是:函数参数不同(类型不同,数量不同,类型顺序不同),但是函数参数相同而返回类型不同构不成重载哦~
名字修饰 :
这个名字修饰其实算是个拓展内容,这里大伟主要结合为什么C++支持函数重载,而C语言为什么不支持。
首先,我们要知道,在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。
其中,预编译阶段会先执行一些预处理指令;然后编译阶段会进行语法分析,词法分析,语义分析,符号汇总等;接着汇编阶段会形成符号表,将汇编指令转换为二进制指令生成 .o 的目标文件;最后链接阶段,合并段表,将符号表合并以及将符号表重定义。
很复杂也看不懂是吧,哈哈(因为大伟也不懂)。那大伟简单点说,就是我们在 .h 文件中声明了一个函数,而在 .cpp 文件中调用了这个函数,在链接阶段会获得函数的地址从而进行调用。而每个编译器都对函数的地址有不同的修饰。以下面的代码为例
int Add(int a, int b)
{
return a + b;
}
void func(int a,int b,int *c)
{
}
int main()
{
Add(1, 2);
func(4, 5, 6);
return 0;
}
由于在Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,下面我们使 用了g++演示了这个修饰后的名字。
通过上面我们可以看出gcc(C语言编译器)的函数修饰后名字不变。而g++(C++编译器)的函数修饰后变成:_Z+函数长度 +函数名+类型首字母。如下:
扩展学习:C/C++函数调用约定和名字修饰规则--有兴趣好奇的铁汁们可以看看,里面有对vs下函数名修饰规则讲解:--------> C/C++ 函数调用约定
OK,到这里大家应该就能理解为什么C++支持函数重载,而C语言不行了。一句话:C++的函数有修饰,而C语言的函数不会修饰,于是就不会区分。
好的啊~ 我们C++的第一节课:新手村到这里也就结束了,大家也就进C++的新手村了,但是各位铁汁不要太骄傲哦~ 冒险,才刚刚开始。
那么本篇博客也就到此为止了,希望大家能够及时复习和练习,下一篇大伟会带大家去冒险者公会或者冒险徽章,还请大家继续支持大伟,拜拜!(╯ε╰)