文章目录
- 前言
- 一.命名空间
- 命名冲突
- 命名空间的使用
- 展开命名空间
- 作用域限定符访问
- 作用域
- 命名空间的合并
- 命名空间的嵌套
- 二.输入输出
- 打印
- 流插入运算符
- 输入
- 流提取运算符
- 三.缺省参数
- 全缺省
- 半缺省
- 跨文件缺省函数参数
- 缺省参数的使用格式
- 四.函数重载
- 参数个数不同
- 参数类型不同
- 参数顺序不同
- 注意事项
- 返回类型不能当做函数重载
- 参数名不能被当做函数重载
- 相同类型的缺省参数不是函数重载
- LInux下的重载函数的符号化
前言
- 因为C++兼容C的大多数语法,所以我们用C逐步讲解,之后再换成C++语法
一.命名空间
- 基本概念 :namespace +空间名+{}
- 切记,最后可没有 ;
命名冲突
#include<stdio.h>#include<stdlib.h>intrand=0;intmain(){printf("%d",rand);return0;}编译时,我们会看到:
结论:与头文件stdlib.h的rand函数的命名冲突了
问题:不改变此变量的名字的前提下,如何正确打印此变量?
答案: 使用命名空间将变量进行封装
注意:命名空间的名字也会发生命名冲突,因此不要起rand!
#include<stdio.h>#include<stdlib.h>namespace shunhua{intrand=0;}intmain(){printf("%d",rand);return0;}- 这样就对了吗?
- 其实不对。
这里其实识别的是rand函数,不是命名空间里的变量!
- 因此:命名空间是将变量或者函数封装,因此是无法直接访问的!
命名空间的使用
展开命名空间
- using namespace + 空间名+ ;
接着上文
#include<stdio.h>#include<stdlib.h>namespace shunhua{intrand=0;}using namespace shunhua;intmain(){printf("%d",rand);return0;}再次编译,看结果
- 这是怎么回事呢?
- 答案 :使用命名空间,相当于将命名空间暴露与全局范围中,因此又回到了我们要最初要解决的问题。
- 命名冲突打印指定变量
- 接着往下讨论
作用域限定符访问
作用域
学过C语言,想必都能看懂这一段代码。
#include<stdio.h>intrand=1;intmain(){intrand=0;printf("%d\n",rand);return0;}- 全局变量与局部变量同名时,优先使用局部变量。
- 换到C++,域是查找变量的默认优先顺序:
- 1.局部域
- 2.全局域
- 3.命名空间访问变量用——展开的命名空间/限定符访问。
作用域限定符:
: :前面要不加默认使用全局变量,前面加命名空间使用的是命名空间的变量
像这样
- :+变量——就用的是全局变量
- 作用域:+变量——就用的是指定的域的变量
#include<stdio.h>namespace shun_hua{intrand=3;}intrand=1;intmain(){intrand=0;printf("%d\n",rand);//局部变量中查找printf("%d\n",::rand);//全局域里面查找printf("%d\n",shun_hua::rand);//在命名空间里面查找return0;}执行结果:
回头解决要解决的问题:
#include<stdio.h>#include<stdlib.h>namespace shunhua{intrand=0;}intmain(){printf("%d",shunhua::rand);return0;}此时再编译没问题,执行一下:
成功打印出命名空间的值
- 命名冲突打印指定变量
命名空间的合并
- 当我们多次定义同名空间时,相当于定义了一个命名空间,同名的命名会自动将变量与函数进行合并,而不是我们想的重命名!
#include<stdio.h>#include<stdlib.h>namespace shun_hua{intrand=0;inty=1;}namespace shun_hua{intx=2;intz=3;}intmain(){printf("%d\n",shun_hua::rand);printf("%d\n",shun_hua::x);printf("%d\n",shun_hua::y);printf("%d\n",shun_hua::z);return0;}- 这里面的命名空间在合并时,是不允许出现相同的函数或变量出现两次的,如果有会直接在语法上,报错。也就是说命名空间的合并是在编译阶段完成的!
- 如果需要在一个命名空间里面出现两个相同变量怎么办呢?
- 命名空间的嵌套
命名空间的嵌套
- 1.命名空间的嵌套是可以使用相同名字的。
- 2.这样展开命名空间编译器会不知道展开哪个,从而报错
#include<stdio.h>namespace shun_hua{intx=0;namespace shun_hua{intx=1;}}//using namespace shun_hua;intmain(){printf("%d\n",shun_hua::shun_hua::x);return0;}输出结果:
二.输入输出
我们首先要明白C++库的基本结构
- 因此C++库是被封装在std命名空间里面的,使用C++库里的对象得通过std访问。
- C++包含头文件是不需要后缀.h
- 输入输出文件在iostream的头文件中
拓展: 早期的头文件在全局域中实现,因此头文件含.h, 后来为了与C头文件区分以及正确的使用命名空间,声明C++的头文件不带.h,因此我们现在看到的iostream不带头文件,而在早期的VC6.0版本还可以使用iostream.h的版本。
打印
流插入运算符
<<跟C语言的左移操作符意义不同,这里是流插入运算符,将数据流入输出流。
打印hello world
#include<iostream>//包含头文件using namespace std;//使用命名空间,这两者缺一不可intmain(){cout<<"hello world\n";return0;}我们一般看到的写法是这样的
#include<iostream>//包含头文件using namespace std;//使用命名空间,这两者缺一不可intmain(){cout<<"hello world"<<endl;//这里的endl其实就是"\n"return0;}- 我们不推荐这样使用命名空间,因为这样将std的命名空间暴露在全局域中,失去了命名空间创建的意义。
一般推荐这样写
#include<iostream>//包含头文件usingstd::cout;usingstd::endl;//这其实是我们使用命名空间的符号的声明intmain(){cout<<"hello world"<<endl;std::cout<<"hello world"<<std::endl;//在使用时也可以这样写,不过在重复多次写这里语句时,比较麻烦。return0;}输入
流提取运算符
- > >与C语言的右移操作符不同,这里是流提取,将数据输进输入流
输入一个整形,并将这个整形打印
#include<iostream>using std::cin;using std::cout;using std::endl;intmain(){intx=0;cin>>x;//这是将输入流的数据读取出来放进xcout<<x<<endl;return0;}- 总结:cout和cin会自动识别类型,不像printf和scanf需要手动的控制其类型,因此还是比较方便的。
特殊的,对于字符指针,不会将地址进行打印,而会打印对应的字符串。
三.缺省参数
- 缺省参数,是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
- 也就是说在函数的指定参数有默认值的情况下,调用函数时,指定参数可以传参,也可不传,即为缺省。
全缺省
- 函数的定义或者声明时,函数的参数都有默认值
#include<iostream>using std::cout;using std::endl;intadd(intx=0,inty=0){returnx+y;}intmain(){cout<<add()<<endl;cout<<add(1,2)<<endl;cout<<add(1)<<endl;//cout<<add(,2)<<endl;//语法规定不行return0;}- 函数缺省,调用时,从左往右进行传参,且从左往右是与函数的参数一 一对应,不能省略的。
半缺省
- 半缺省指的是一部分参数缺省,缺省参数只能从右往左进行缺省
- 注意:可不是一半的参数缺省
- 缺省顺序:只能从右向左进行缺省,而不能从左向右进行缺省。这是因为函数在传参时从左向右进行传参的。
#include<iostream>using std::cout;using std::endl;intadd(intx,inty=0){returnx+y;}intmain(){cout<<add(1)<<endl;cout<<add(1,2)<<endl;return0;}- 用途:在单链表初始化时,可以指定开辟大小,也可以指定默认参数。
跨文件缺省函数参数
add.h文件
intadd(intx=0,inty=0);add.cpp文件
#include"add.h"intadd(intx,inty){returnx+y;}test.cpp文件
#include"add.h"#include<iostream>using std::cout;using std::endl;intmain(){cout<<add(1)<<endl;cout<<add(1,2)<<endl;return0;}- 情况:缺省参数的函数定义与声明在不同文件中
- 在函数声明中需声明缺省参数,定义则不用写缺省参数,否则会出现重定义。
- 原因:头文件的函数声明,在编译期间就会被识别,相当于先给编译器一个承诺,函数是什么样子的,而函数定义是在链接期间被检查的,因此声明时前提(承诺),定义是结果(无需写缺省参数)。
缺省参数的使用格式
- 缺省参数只能用常量或者具有全局属性的变量
#include<iostream>usingstd::cout;usingstd::endl;#defineMAX100//常量intx=0;//全局变量intadd(intmax=MAX,intmin=x){returnmax+min;}intmain(){cout<<add()<<endl;return0;}四.函数重载
重载,顾名思义就是一词多义,比如比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了(乒乓)!”,后者是“(国足)谁也赢不了!”。
函数重载就是函数同名不同义。
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同常用来处理实现功能类似数据类型不同的问题
参数个数不同
#include<iostream>using std::cout;using std::endl;intadd(){return0;}intadd(intx){returnx;}intmain(){cout<<add()<<endl;cout<<add(1)<<endl;}参数类型不同
#include<iostream>using std::cout;using std::endl;intadd(intx,inty){return0;}intadd(doublex,doubley){return0;}intmain(){cout<<add(1,1)<<endl;cout<<add(1.0,1.0)<<endl;}参数顺序不同
#include<iostream>using std::cout;using std::endl;intadd(intx,doubley){return0;}intadd(doubley,intx){return0;}intmain(){cout<<add(1,1.0)<<endl;cout<<add(1.0,1)<<endl;}注意事项
返回类型不能当做函数重载
- 函数重载是指的函数调用,所发生的类型识别和参数个数,从而确定调用哪个同名函数,而函数的返回值是不能根据函数调用进行确定的
示例:
- 首先说明此代码会报错,原因是在函数调用时,不能区分返回类型,因此调用存在歧义。
#include<iostream>usingstd::cout;usingstd::endl;intadd(intx,inty){return0;}floatadd(intx,inty){return0;}intmain(){cout<<add(1,0)<<endl;cout<<add(1,1)<<endl;}编译结果:
参数名不能被当做函数重载
#include<iostream>usingstd::cout;usingstd::endl;intadd(intx,inty){return0;}intadd(inty,intx){return0;}编译结果:
相同类型的缺省参数不是函数重载
示例:
#include<iostream>using std::cout;using std::endl;intadd(intx,inty=0){return0;}intadd(intx,inty){return0;}编译结果:
error: redefinition of 'int add(int, int)',即为重定义了函数、
LInux下的重载函数的符号化
Linux下gcc编译的结果
结论:函数符号化为函数本身的名字
Linux下g++编译的结果g++编译的生成的函数符号名的规则:_Z+函数名长度+函数名+参数类型的首字母
总结:C++本身其实不是通过函数名进行查找,而是通过函数符号化之后的结果,访问地址从而调用函数。
补充:关键字
- export关键字,C++11废除了这个 export关键字的含义,但保留这个关键字,供以后使用。
这个关键字是为了驯服模板声明与定义分离而设置的关键字,可惜功能太次被废掉了。