C++入门(命名空间,缺省参数,函数重载详解)

目录
1. C++关键字(C++98)
命名冲突:
2. 命名空间:namespace关键字
2.1 命名空间定义
普通命名空间例子:
1.域作用限定符 ::
2.如何访问命名空间域内的变量:
3.不同命名空间中的同名变量如何使用:
4.命名空间的性质
细节1:这里n1是结构体,结构体已经升级成类,就可以不加struct
细节2:命名空间不影响声明周期,只是隔离了名字冲突,a还是全局变量
细节3:命名空间不能放在main函数中,只能放在全局
细节4:命名空间一般是放在头文件中
2.2 命名空间使用
1.using namespace byte ;
例子1:
例子2:using namespace byte: :cache
例子3:
例子4:
2.using namespace std;
3. C++输入&输出
(1.cin和cout讲解:
(2. C++输入输出更方便,
(3.输出支持空格 冒号分割
(4.想保留小数位数还是用c语言吧,他们输入输出可以混着用,c++也能控制但是很复杂,不建议学
4. 缺省参数/默认参数
4.1 缺省参数概念
4.2 缺省参数分类
(1.多个缺省参数:
(2.缺省参数的意义:
(3.总结:
5. 函数重载
5.1 函数重载概念+详解
为什么C语言不支持重载,C+ +支持重载?详解:

1. C++关键字(C++98)
C++总计63个关键字,C语言32个关键字
ps:下面我们只是看一下C++有多少关键字,不对关键字进行具体的讲解。后面我们学到以后再细讲。
#includ:相当于C语言里面的
using namespace std; 又是什么东西呢,接下来由此引入命名冲突和命名空间关键字 namespace
命名冲突: 命名冲突:同一个作用域不能定义同名变量 -- C语言没有很好的解决这个问题,CPP引入namespace解决这个问题
int rand = 0; int main() { printf("%d\n", rand); return 0; } 此时没问题,但是包含某些库的时候就会报错: #include //命名冲突 int rand = 0; //命名冲突 int main() { printf("%d\n", rand); return 0; }
命名冲突 -- C语言没有很好的解决这个问题,CPP引入namespace解决这个问题
2. 命名空间:namespace关键字 在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作
用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字
污染,namespace关键字的出现就是针对这种问题的
2.1 命名空间定义 定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名
空间的成员。
普通命名空间例子:
(1)
【C++入门(命名空间,缺省参数,函数重载详解)】C++入门(命名空间,缺省参数,函数重载详解)
文章图片

此处打印的是函数地址,是stdlib.h中的一个创造随机值函数rand的地址
因为命名空间关键字namespace把变量rand=0关进了名叫bit的命名空间域中,隔离起来
(2)

#includevoid f() {} int f = 0; int main() { printf("%p\n", f); } ————————这样写就不对,改成下面这样就对了: #includenamespace bit // 命名空间域 { int f = 0; } void f() {} int main() { printf("%p\n", f); }

同名变量在不同域可以存在:
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

局部有限,则打印1,如果找不到局部变量才打印0
注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
1.域作用限定符 :: (1)情景1 ::a 左边域是空白(左边有没有空格无所谓),默认访问全局域的a
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

(2)情景2 假如一个命名空间叫bit,在其中定义了变量f和rand ,想用 f 或 rand ,就要展开bit写成 bit::f 和 bit::rand
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

(3)情景3 假如一个命名空间叫zsh,在其中定义了一个结构体类型 ListNode ,用这个类型定义变量
namespace zsh { int a = 0; void f() { printf("void f()\n"); } struct ListNode { int val; struct ListNode* next; }; } 可以这样定义变量: zsh::ListNode* n1=NULL ; //结构体指针 struct zsh::ListNode* n1 = NULL; zsh::ListNode n2 ; //结构体变量 struct zsh::ListNode n2;
2.如何访问命名空间域内的变量: C++入门(命名空间,缺省参数,函数重载详解)
文章图片

3.不同命名空间中的同名变量如何使用: #include#includenamespace zsh { int a = 0; void f() { printf("void f()\n"); } struct ListNode { int val; struct ListNode* next; }; } namespace bit { struct ListNode { int val; struct ListNode* next; }; struct QueueNode { int val; struct QueueNode* next; }; } int main() { zsh::ListNode* n1 = NULL; bit::ListNode* n2 = NULL; return 0; }
4.命名空间的性质 1、同名的命名空间是可以同时存在的,编译器编译时会合并
2、命名空间可以嵌套
3. 命名空间中的内容,既可以定义变量,也可以定义函数,可以定义类型(结构体类型)
(这里的n1是结构体,再使用时不用带前面的类型)
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

细节1:这里n1是结构体,结构体已经升级成类,就可以不加struct
(左边是c++写法,右边是严格c语言写法)
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

细节2:命名空间不影响声明周期,只是隔离了名字冲突,a还是全局变量
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

细节3:命名空间不能放在main函数中,只能放在全局
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

细节4:命名空间一般是放在头文件中
2.2 命名空间使用 命名空间中成员该如何使用呢?比如:
命名空间的使用有三种方式:
加命名空间名称及作用域限定符
使用using将命名空间中成员引入
使用using namespace 命名空间名称引入
1.using namespace byte ; //这里的意思是把byte这个命名空间定义的东西放出来,使namespace byte这个命名空间无效
例子1:
前面已经有同名命名空间:
namespace byte { int b = 0; namespace cache { struct Node { int val; struct Node* next; }; } }namespace byte { // a还是全局变量,命名空间不影响生命周期 int a = 0; namespace data { struct Node { int val; struct Node* next; }; } }

C++入门(命名空间,缺省参数,函数重载详解)
文章图片

如果先展开data再展开byte就错了
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

例子2:using namespace byte: :cache
只是展开了byte里的cache,那么可以把byte: :cache省了,原本是byte: :cache::Node n1 ,现在写成 struct Node n1 ;
但是不能只省byte ,写成struct cache: :Node n2; 就错了
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

例子3:
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

如果都放出来,data和cache中都有struct Node 这个结构体,就又重名了,就错了
最规范的还是展开一个byte
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

例子4:
直接using namespace bit; 会全部放出来,虽然能用f了,但是也把rand放出来了,变量rand和stdlib.h 中的函数rand又同名了,就错了
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

所以要用什么放什么:
单独放不用加namespace,这是语法规定
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

2.using namespace std; std是c++标准库的命名空间,#include 是c++头文件
using namespace std;就是展开c++头文件的内容
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

如果不写这句就需要指定命名空间std里的内容 std::cout
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

如果下面这样放开了std,再定义cout就和库里面的某些函数冲突了,一用cout就会报错
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

干脆不放开,然后指定使用命名空间std里面的内容,比如std::cout或者std::endl就可以使用
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

只放cout,指定不指定都可以
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

不能连着放
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

3. C++输入&输出 新生婴儿会以自己独特的方式向这个崭新的世界打招呼,C++刚出来后,也算是一个新事物,
那C++是否也应该向这个美好的世界来声问候呢?我们来看下C++是如何来实现问候的。
说明:
1. 使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空间。
注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件
即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文
件不带.h;旧编译器(vc 6.0)中还支持格式,后续编译器已不支持,因此推荐使用
+std的方式。
(1.cin和cout讲解: cin和cout看成控制台,>>流提取运算符和
cin>>a ,箭头方向由cin指向a,相当于cin内数据流入a
cout
endl相当于换行
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

(2. C++输入输出更方便, 不需增加数据格式控制,比如:整形--%d,字符--%c
一行输入多个,一行输出多个,且不用定义格式,自动控制输出
endl相当于换行,这里用endl和\n是一样的
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

(3.输出支持空格 冒号分割 C++入门(命名空间,缺省参数,函数重载详解)
文章图片

(4.想保留小数位数还是用c语言吧,他们输入输出可以混着用,c++也能控制但是很复杂,不建议学 C++入门(命名空间,缺省参数,函数重载详解)
文章图片

(5.scanf和printf比cin和cout快一些,大量输出时有可能用,平时不考虑
4. 缺省参数/默认参数 大家知道什么是备胎吗?
C++中函数的参数也可以配备胎。
4.1 缺省参数概念 缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
这里的int a=0 就是缺省参数
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

4.2 缺省参数分类 (1.多个缺省参数:
全缺省:缺省参数给全了
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

多个缺省参数,只能传完第一个再传第二个,不能直接传第二个
半缺省:缺省参数给了一部分,即缺省部分
①最少传一个(第一个),不能一个不传
②半缺省 必须从右往左缺省,并且是连续的
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

必须从右往左缺省,并且是连续的例子:
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

(2.缺省参数的意义:
struct Stack { int* a; int size; int capacity; }; void StackInit(struct Stack* ps, int n = 4) { assert(ps); ps->a = (int*)malloc(sizeof(int)*n); ps->size = 0; ps->capacity = n; }int main() { TestFunc(1); TestFunc(1, 2); TestFunc(1, 2, 3); Stack st; //StackInit(&st); //不给参数就是缺省参数,n=4 StackInit(&st, 100); //也可以给参数,n=100 return 0; }

(3.总结:
1. 半缺省参数必须从右往左依次来给出,不能间隔着给
2. 缺省参数不能在函数声明和定义中同时出现(函数声明和函数定义分离的情况)
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

(解释:怕你用不同的缺省参数
那该怎么给?缺省参数和声明在编译阶段处理!
声明定义都给缺省参数不行,存在歧义
声明不给定义给缺省参数不行,如果只给定义里面了,头文件#include "Queue.h" 在声明里面找不到缺省参数就报错,函数定义是在链接时连接起来的
只能声明给定义不给缺省参数,因为头文件#include "Queue.h" 展开,.cpp向上找会找到声明里面的缺省参数,)
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

3. 缺省值必须是常量或者全局变量
4. C语言不支持(编译器不支持)
5. 函数重载 自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。
比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前
者是“谁也赢不了!”,后者是“谁也赢不了!”
5.1 函数重载概念+详解 函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题
例题:
A.int compare(double,double)
B.double compare(double,double)
C.double compare(double,int)
D.int compare(int,int)
只要参数列表不一样,就构成函数重载,ABC都对,D函数重载不能依靠返回值的不同来构成重载,因为调用时无法根据参数列表确定调用哪个重载函数,故错
正确例子:
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

错误例子:
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

正确:
正确: // 顺序不同 void f(int i, double d) { cout << "void f(int i, double d)" << endl; }void f(double i, int d) { cout << "void f(double i, int d)" << endl; } int main() { f(1, 22.2); f(22.2, 1); }

C++入门(命名空间,缺省参数,函数重载详解)
文章图片

意义:使用相同功能的函数时,如果类型不同可以使用函数重载
void swap(int* p1, int* p2) { int x = *p1; *p1 = *p2; *p2 = x; }void swap(double* p1, double* p2) { double x = *p1; *p1 = *p2; *p2 = x; }int main() { int a = 0, b = 1; double c = 1.1, d = 2.2; swap(&a, &b); swap(&c, &d); return 0; }

为什么C语言不支持重载,C+ +支持重载?详解:
举例说明:有三个文件头文件 f.h 和 c++文件 f.cpp , test.cpp
//f.h#include void f(int a,double d); void f(double d,int a); //f.cpp#include"f.h" void f(int a, double b) { printf("%d, %f\n", a, b); } void f(double b,int a) { printf("%f, %d\n",b,a) ; }//test.cpp#include"f.h" int main( ) { f(1,2.222) ; f(2.222, 1) ; return 0; }

C++入门(命名空间,缺省参数,函数重载详解)
文章图片

编译链接过程:
1.预处理:预处理会把头文件展开到cpp文件中,f.h就没了,同时宏替换,条件编译,去注释,f.cpp 和test.cpp变为f.i 和 test.i 文件
2.编译:检查语法,生成汇编代码,f.i 和 test.i 文件 转化成 f.s 和 test.s文件
3.汇编:把汇编代码转换成二进制的机器码,f.s 和 test.s文件 转化成 f.o 和 test.o文件
4.链接:找调用函数的地址,链接对应上,合并到一起,把f.o 和 test.o合并成a.out。
汇编后:.o文件中有 函数调用指令 和 符号表
符号表:记录了函数定义和函数名的和函数地址映射关系 还有其他的东西暂时先不用管
C++入门(命名空间,缺省参数,函数重载详解)
文章图片

main函数调用指令中去调用两个 f函数 时,会有一句指令叫call 函数名(函数地址),还未链接时,test.cpp中没有函数定义,call指令只需要找函数声明,声明是一种承诺,承诺函数定义在别的文件中,有了"承诺"后call指令可以先不知道函数地址,随后进行链接,链接是把 f.o 和 test.o 里面所有的指令链接起来成为一个文件叫 a.out ,此时兑现"承诺",call指令通过函数的名字去上面的符号表里面找到函数地址把“?未知地址”添上函数地址才能成功执行call指令(符号表汇总了函数名的和函数地址映射关系),但是:c语言中call后面的函数名就是原来的函数名,没有修改,没有区别,如果函数名相同,再去找函数地址就会出问题,因为无法区分两个同名函数。c++正是对函数名做了修饰进行区分才能够进行函数重载:C++入门(命名空间,缺省参数,函数重载详解)
文章图片

函数名不再是原本的函数名了,而是:_Z函数名长度 函数名 类型首字母的形式进行记录函数,c++把参数类型首字符带进命名规则中去了,因此去找函数地址就可以区分同名函数,这也说明了为什么函数重载需要 形参个数 或 类型 或 顺序 不同了。

    推荐阅读