腾讯面试题只是“Hello World”?深度理解命名空间与函数重载的原理(C++入门详解)

命名空间

无论学习编程语言,开始入门的“Hello World”是必不可少的。

#include<iostream>
using namespace std;
int main()
{
    
    
count<<"hello world"<<endl;
return 0;
}

看起来很简单,但是深究起来却有很大的学问。没错这其实是一位学长的腾讯面试题。是不是有点怀疑人生,其实面试官只是借助着一个简单的程序深挖了背后的底层原理。

命名空间概念

先来看一个概念叫做命名空间。

#include<stdio.h>
//命名空间
int scanf=0;//c不能用关键字作为变量名,但是函数没有规定,所以按理来说应该是可以的
int main()
{
    
    
printf("%d",scanf);
return 0;
}

但是却有这么一个错误。
在这里插入图片描述
我们知道在预处理的时候会展开头文件,scanf函数在里面,所以这里是有歧义,在我们写项目的时候会出现同样的问题,假如出现了同样的命名,在链接合成同一个文件的时候,那声明成static可以解决吗,static是解决一个全局变量在多个文件进行编译冲突问题,解决不了命名的这个问题,显然C语言对这个问题没有办法,Cpp通过命名空间来改变来解决这个问题。

#include<stdio.h>
//命名空间,域
namespace bit
{
    
    
int scanf=0;
}
int main()
{
    
    
printf("%d",scanf);
return 0;
}

编译成功
在这里插入图片描述
输出竟然是这么大,为什么呢?
在这里插入图片描述
我们在代码里写的命名空间域还没有使用他,将它隔离起来,头文件展开的时候跳过,所以这里打印的是scanf的地址,严格来说应该打印%p,就打印了他的地址

namespace bit
{
    
    
int scanf=0;
}

命名空间应用

他本质还是一个全局变量,要访问它有三种方法。
第一种是通过域作用限定符直接用。

printf("%d",bit::scanf);

第二种是单独展开特定的变量

namespace bit
{
    
    
int a=0;
int b=0;
int c=0
}
using bit::b;
int main()
{
    
    
printf("%d",b);
return 0;
}

第三种很粗暴,也就出现了文章开始的,我们经常用的那一种格式

namespace bit
{
    
    
int a=0;
int b=0;
int c=0
}
using namespace bit;
int main()
{
    
    
printf("%d",a);
printf("%d",b);
printf("%d",c);
return 0;
}

在写大型项目时,我们用第一种或者第二种进行展开。
在Cpp训练时,我们所需要所有的库便是在这个std中,通常选择全部展开。

using namespace std;

命名空间嵌套

在这里插入图片描述
在这里插入图片描述
不同文件也可以有同名命名空间,链接时会合成一个。

io流

iostream

要使用cin(键盘),cout(控制台)。首先便是要包含头文件

include<iostream>

然后便是展开std命名空间,三种方式。
语法格式:

//可以认为字符串的东西流向cout
cout<<"hello";
//想要换行
cout<<"hello"<<endl;

自动识别内容,无需c语言一样指定格式
<< 和>>是运算符,cin和cout是对象

int i=0;
cin>>i;

当有不同类型变量的时候,用cin,cout

int main()
{
    
    
int i;
double d;
cin>>i>>d;
cout<<i<<d<<endl;
}

当这种情况,我们想要输出一些格式做一些说明,或者想让他有序一点,用printf更合适

struct Student
{
    
    
   char name[10];
   int age;
};
int main()
{
    
    
int i;
double d;
cin>>i>>d;
cout<<i<<d<<endl;
struct Student s={
    
    "peter",18};
printf("name:%s age:%d\n",s.name,s.age);
}

这种挺复杂的
在这里插入图片描述

函数重载

缺省

先来看个概念
缺省:声明或定义的时候为函数的参数制定一个默认的值。
在这里插入图片描述
缺省还分为全缺省和半缺省

全缺省意思就是形参全部指定。
半缺省部分指定必需要从右向左给值。

缺省参数不能再函数声明和定义中同时出现。
就算缺省值一样也不行,必须在声明时给好

在这里插入图片描述

函数重载概念

函数的一种特殊情况,Cpp允许在同一作用域种声明功能类似的同名函数,这些同名函数的形参列表
(参数个数或类型或顺序)必须不同。

c++函数重载实现原理

假设当前有这么几个文件 test.h , test.cpp , main.cpp
经过这么几个过程

预处理:头文件展开,宏替换,条件编译

test.cpp->test.i      main.cpp->main.i

编译:检查语法,生成汇编代码

test.i->test.s    main.i->main.s

汇编把汇编代码转换成二进制机器码

test.s->test.o          main.s->main.o

链接

-o形成可执行文件

生成汇编的时候通过call 函数,他不知道自己找的是什么(call_(?)),只能找到函数声明,知道了函数的名字
只有在链接时会在其他文件的符号表中通过函数名找,拿到地址。

windows查看底层原理太复杂,我们在Linux环境下查看。
先简单编一个c语言文件
在这里插入图片描述
通过objdump指令查看
我们可以看到c语言在调用时直接调用的函数名,多个相同的文件
在这里插入图片描述
再来看c++
在这里插入图片描述
查看obj文件
在这里插入图片描述
可以明显的看到c++与c语言的不同,c++使用了一个东西叫函数修饰规则。
通过_z[]+函数名+类型首字母,c++的重载函数只要参数不同修饰的名字就不同,这样链接的时候就会找到。
C语言没有修饰规则,所以直接通过名字去找,有同名就冲突了。

猜你喜欢

转载自blog.csdn.net/qq_45928272/article/details/113484456