【C++】命名空间输入输出缺省参数函数重载
创始人
2024-01-16 16:43:35
0

​🌠 作者:@阿亮joy.
🎆专栏:《吃透西嘎嘎》
🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根
在这里插入图片描述

目录

    • 👉什么是C++👈
    • 👉C++关键字(C++98)👈
    • 👉命名空间👈
      • 命名空间定义
      • 命名空间使用
    • 👉C++输入&&输出👈
    • 👉缺省参数👈
      • 缺省参数概念
      • 缺省参数分类
    • 👉函数重载👈
      • 函数重载概念
      • C++支持函数重载的原理
    • 👉总结👈

👉什么是C++👈

  C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了 OOP(object oriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。
 1982年,Bjarne Stroustrup博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。因此,C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计

在这里插入图片描述

👉C++关键字(C++98)👈

C++总计 63 个关键字,而C语言只有 32 个关键字。下面是 C++的关键字,这些关键字会在后面的博客细讲。

在这里插入图片描述

👉命名空间👈

在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染namespace关键字的出现就是针对这种问题的。

看一下下面的例子:

在这里插入图片描述

此时的变量名和stdlib头文件中的rand函数冲突了,此时我们可以借助 C++的命名空间来解决这个问题。

命名空间定义

定义命名空间,需要使用到 namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。

在这里插入图片描述

此时,我们将整型rand定义在命名空间Joy中,这就不会和库函数中的rand函数产生命名冲突了。一般来说,在开发中是用项目名字作为命名空间的名字。需要注意的是,上面程序打印的值是rand函数的地址,而不是我们定义的整型变量rand的值。那为什么会这样呢?这时候,我们就需要编译器的查找规则。

编译器的查找规则:编译器首先在局部域中找,如果在局部域中找不到,编译器就会去全局域中找。全局域中有在预处理时展开的头文件,那么编译器就在全局域中找到了rand,然后打印rand函数的地址。值得注意的是:如果在全局域中还找不到的话,编译器也不会去命名空间中找。

在这里插入图片描述

命名空间中,除了可以定义变量,还可以函数、结构体和命名空间嵌套定义等等。

namespace N1
{// 命名空间中可以定义变量/函数/类型int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}// 命名空间可以嵌套
namespace N2
{int a;int b;int Add(int left, int right){return left + right;}namespace N3{int c;int d;int Sub(int left, int right){return left - right;}}
}

当一个工程文件中存在着多个相同名称的命名空间,编译器最后会将里面的内容合并在同一个命名空间中。见下面的例子:

// test.h中的命名空间N1
namespace N1
{int Mul(int left, int right){return left * right;}
}// test.cpp中的命名空间N1
namespace N1
{int Add(int left, int right){return left + right;}
}

注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。

现在,我们已经知道了命名空间的概念了。那如何去使用命名空间里的成员呢?我们来学习一下。

命名空间使用

以下面的命名空间N为例,我们来学习命名空间的三种使用方式。

namespace N
{int a = 10;int b = 20;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}

命名空间的三种使用方式

  • 加命名空间名称及作用域限定符

    在这里插入图片描述

  • 使用using将命名空间中某个成员引入

    在这里插入图片描述

  • 使用using namespace 命名空间名称 引入

    在这里插入图片描述

👉C++输入&&输出👈

在上面讲到了命名空间可以放变量和函数的定义等等,其实 C++ 标准库的定义实现也是放在命名空间中的,这个命名空间就是std。其实这么做也是为了避免命名冲突,还可以起到保护的作用。

因为 C++标准库的定义实现都是放在命名空间中的,所以我们使用这些函数也要遵循命名空间的使用规则。

那我们现在就来用 C++ 来写一下经典的代码hello world吧!

在这里插入图片描述
知道了如何用 C++写hello world,那么我们就来学如何读取输入数据。

在这里插入图片描述
C++ 中的输入和输出可以自动识别类型,这是相较于C语言中scanfprintf的优势。不过想要用coutcin控制浮点数输出精度,控制整形输出进制格式等等,这就会比较复杂了。这时候,我们就可以结合着 C语言来使用,就是那个使用起来方便就使用哪一个。见下图:

在这里插入图片描述

注意:以上的将命名空间的内容展开这种使用方式是简单了,但是标准库就全部暴露出来了,就有可能存在命名冲突问题。不过,我们在日常练习或者写小程序的时候可以这样写,但是在项目里最好不要用。除了将命名空间全部展开,我们还可以将常用的指定展开,如using std::cout,只需要注意定义变量或者函数的时候避免命名冲突就可以了。

说明:

  • 使用cout标准输出对(控制台和cin标准输入对象键盘时,必须包含iostream头文件 以及按命名空间使用方法使用std。
  • cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
  • <<是流插入运算符,>>是流提取运算符
  • 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。 C++的输入输出可以自动识别变量类型
  • 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识, 这些知识我们我们后续才会学习,所以我们这里只是简单学习他们的使用。后面我们还有有 一个章节更深入的学习IO流用法及原理。

注意:
早期标准库将所有功能在全局域中实现,声明在 .h 后缀的头文件中,使用时只需包含对应头文件即可,后来将其实现在 std 命名空间下,为了和 C 头文件区分,也为了正确使用命名空间, 规定C++头文件不带 .h;旧编译器(vc 6.0)中还支持 格式,后续编译器已不支持,因此推荐使用+std的方式。

👉缺省参数👈

缺省参数概念

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。

这是什么意思呢?请看下方代码:

#include 
using namespace std;// 缺省参数
void Func(int a = 0)
{cout << a << endl;
}
int main()
{Func(); // 没有传参时,使用参数的默认值Func(10); // 传参时,使用指定的实参return 0;
}

在这里插入图片描述

缺省参数分类

  • 全缺省参数
#include 
using namespace std;void Func(int a = 10, int b = 20, int c = 30)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;
}int main()
{Func();Func(1); // 传给第一个Func(1, 2); // 传给第一个和第二个Func(1, 2, 3);//Fun(1, , 3); // 错误的调用方式return 0;
}

在这里插入图片描述

  • 半缺省参数
#include 
using namespace std;void Func(int a, int b = 10, int c = 20)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;
}int main()
{Func(1);return 0;
}

有了缺省函数,我们就可以有下面的玩法了。

#include 
struct Stack
{int* a;int top;int capacity;
};void StackInit(struct Stack* ps, int defaultCP = 4)
{ps->a = (int*)malloc(sizeof(int) * defaultCP);assert(ps->a);ps->top = 0;ps->capacity = defaultCP;
}int main()
{// 不知道要插入多少数据struct Stack st1;StackInit(&st1);// 知道要插入100个数据struct Stack st2;StackInit(&st2, 100);
}

注意

  • 半缺省参数必须从右往左连续缺省,不能间隔缺省
  • 缺省参数不能在函数声明和定义中同时出现。如果声明与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值。
  • 缺省值必须是常量或者全局变量
  • C语言不支持(编译器不支持)

👉函数重载👈

自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!”

函数重载概念

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数或类型或类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。

参数类型不同

#include 
using namespace std;int Add(int left, int right)
{return left + right;
}double Add(double left, double right)
{return left + right;
}int main()
{cout << Add(1, 2) << endl;cout << Add(1.1, 2.2) << endl;return 0;
}

在这里插入图片描述

这也是 C++ 相较于 C语言的优势,其实就是编译器能够自动识别类型,本质就是函数重载支持。

个数不同

#include 
using namespace std;void f()
{cout << "f()" << endl;
}void f(int a)
{cout << "f(int a)" << endl;
}int main()
{f();f(1);return 0;
}

在这里插入图片描述

顺序不同

#include 
using namespace std;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;
}int main()
{f(0, 'A');f('A', 0);return 0;
}

在这里插入图片描述
注意:顺序不同是形参类型顺序不同,以下的代码不是顺序不同,并不构成函数重载。

void f(int b, int a)
{cout << "f(int b, int a)" << endl;
}void f(int a, int b)
{cout << "f(int a, int b)" << endl;
}

含数重载与缺省参数

#include 
using namespace std;// 构成函数重载
void f()
{cout << "f()" << endl;
}void f(int a = 0, char b = 1)
{cout << "f(int a, char b)" << endl;
}int main()
{f(10);f(10, 20);return 0;
}

注意:以上的函数构成函数重载,但是调用f()会报错,存在歧义。

C++支持函数重载的原理

为什么C++支持函数重载,而C语言不支持函数重载呢?

在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。C /C++在编译链接的时候,会生成符号表。不过 C语言 和 C++ 生成的符号表是不一样的。C语言的符号表直接是函数名+地址,而 C++ 的符号表是经过修饰后的函数名+地址。所以 C语言不会支持同名函数,也就是不支持函数重载,而 C++是支持函数重载的。

在这里插入图片描述

结论:在 linux 下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中

通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。而不同的编译器下,函数名的修饰规则可能会不一样。

Windows下名字修饰规则

在这里插入图片描述
对比Linux会发现,windows下vs编译器对函数名字修饰规则相对复杂难懂,但道理都是类似的,我们就不做细致的研究了。

相信大家都知道函数名修饰规则,那我问大家一个问题:. 如果两个函数函数名和参数是一样的,返回值不同是否构成函数重载。相信很多同学可能会说构成函数重载,因为我们只需要在函数名前面加上函数的返回值类型标识就好了。其实这不是真正的原因,就算函数名修饰时加上函数的返回值类型也会出现问题,因为在调用函数的时候没有办法指定函数的返回值类型。

在这里插入图片描述

函数名和参数是一样的,返回值不同的函数不构成重载的真正原因并不是函数名修饰规则,而是调用时的二义性,调用时不指定函数的返回值类型,无法区分调用哪一个函数。

👉总结👈

在本篇博客里,我们学习了C++的命名空间、输入和输出、缺省参数以及函数重载。这也意味着我们已经步入了C++,希望我们一起努力吃透C++。以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家啦!💖💝❣️

相关内容

热门资讯

绿豆观察日记 关于绿豆观察日记范文7篇  一天又结束了,心中一定有不少感想,立即行动起来写一篇日记吧。那么什么样的...
魔法森林童话作文 魔法森林童话作文3篇  在日常学习、工作抑或是生活中,大家都写过作文,肯定对各类作文都很熟悉吧,作文...
种植向日葵观察日记 种植向日葵观察日记(精选6篇)  即将要到一天的结尾了,相信你会领悟到不少东西,不妨坐下来好好写写日...
写给十年后的自己作文 写给十年后的自己作文(精选26篇)  在平平淡淡的日常中,大家总免不了要接触或使用作文吧,作文是从内...
童话王国作文 【精选】童话王国作文8篇  在平日的学习、工作和生活里,许多人都写过作文吧,借助作文可以宣泄心中的情...
我的理想优秀小学生作文 我的理想优秀小学生作文(精选52篇)  在日常学习、工作抑或是生活中,大家都写过作文吧,写作文可以锻...
我的课余生活作文400字 我的课余生活作文400字(通用62篇)  在日常学习、工作和生活中,大家对作文都不陌生吧,作文是一种...
金乌和玉兔趣味童话故事 金乌和玉兔趣味童话故事  金色的太阳里,住着一只长着三只脚的金色乌鸦。银色的月亮里,住着一只洁白的玉...
未来的交通作文 未来的交通作文(15篇)  在平时的学习、工作或生活中,许多人都写过作文吧,借助作文可以宣泄心中的情...
黄豆的观察日记 黄豆的观察日记(通用31篇)  不知不觉中一天又要结束了,我们一定有不少所感触的事情吧,让我们今天做...
展开想象的翅膀作文 展开想象的翅膀作文3篇  在日复一日的学习、工作或生活中,说到作文,大家肯定都不陌生吧,作文是通过文...
写给初三的自己作文 写给初三的自己作文9篇  在平平淡淡的日常中,说到作文,大家肯定都不陌生吧,借助作文人们可以实现文化...
经典童话故事 经典童话故事(精选27个)  童话故事是指儿童文学的一种体裁,童话中丰富的想象和夸张可以活跃你的思维...
我学会了自己去上学作文 我学会了自己去上学作文  在日常学习、工作或生活中,大家总少不了接触作文吧,作文是通过文字来表达一个...
答自己问作文 答自己问作文(精选25篇)  在平日的学习、工作和生活里,大家都不可避免地会接触到作文吧,写作文是培...
我学会了游泳作文 我学会了游泳作文(通用10篇)  在平平淡淡的学习、工作、生活中,许多人都写过作文吧,作文根据写作时...
观察蚂蚁日记 观察蚂蚁日记(通用25篇)  不知不觉中一天又要结束了,相信你有很多感悟吧,让我们今天做个总结,写一...
辣椒树散文 辣椒树散文  奶奶说,一个人住吃用不了多少,辣椒都像树一样大,摘几颗下来,足可以吃好几餐。  奶奶姓...
诗词小达人作文 诗词小达人作文  在日常的学习、工作、生活中,大家都不可避免地要接触到作文吧,作文要求篇章结构完整,...
一年级孩子听的睡前童话故事 一年级孩子听的睡前童话故事精选【四篇】一年级孩子听的睡前童话故事精选【四篇】1  长臂猴的尴尬  黑...