C++自制心得——开篇(缺省函数+函数重载)
前言:
本心得只适合给那些拥有C语言基础 (系统的自主学习过C语言(以找工作为目标,学校老师教的一律视作没学),了解一些底层机制,用C实现过一些基本数据结构 (顺序表、链表、队列与栈、初等二叉树、十大经典排序等) ) 的人观看。如果你不满足上述条件就不要在这里浪费时间了。
本人在写专栏上的技术力并不好,如果你觉得这篇文章在排版上有需要改进的地方可以在评论区留言并附上具体操作流程。
本人目前是大二在读生,目前刚开始学习C++相关知识,如果有大佬发现哪里介绍的不对或者有疏漏欢迎在评论区留言,我尽量在发现的第一时间纠正。
好,废话不多讲,我们进入正题。
缺省函数
test.cpp
slist.h
slist.cpp
这是一个简单顺序表的C代码(.cpp环境下NULL有一些历史遗留问题,换成了C++的nullptr),跑起来肯定没问题,但是这里有个让人不爽的地方。在slist.h里,我们用宏定义了一个默认初始化大小,一般情况下这个值是100,如果数据量多于这个值就会去扩容,这个逻辑看着还能接受。那如果出现了某些极端情况会怎么样?让代码跑起来。

看看控制台上满屏幕的异地扩容,问题的严重性跃然纸上。哪怕不算频繁拷贝带来的性能浪费,这个方案所花费的时间也已经达到了一步到位的近两倍。显然,在C语言里为了避免这一现象的发生,我们需要额外的函数来处理非默认情况下的空间开辟。
好吧,我承认我懒得再敲一个函数,那么C++有没有办法用一个函数解决默认+非默认的情景?现在,请出我们的缺省函数(你可以认为缺省 == 默认),然后再跑一遍代码。

slist.cpp(修改的部分)
slist.h
test.cpp
上面的代码有点复杂,我们来看个简单的。
test.cpp

显然,缺省函数比常规函数多了一个备胎机制,如果你给了值,缺省函数就用你的值,你不给值,缺省函数就用备胎的值。
全缺省函数
函数当然可以有多个缺省值,如果一个函数的所有形参均拥有缺省值,那它就是全缺省函数,such as:
test.cpp

我知道你想干什么,但是不行,你不能这么传。

缺省函数存在多个缺省值时,只可从左向右传参。
半缺省函数
常规形参与缺省形参也能一起用,这样的函数也叫半缺省函数。
test.cpp

大胆的想法也可以收一收了,缺省函数存在多个缺省形参时,只可从右向左确定缺省形参,且所有的缺省形参必须在常规形参的右边。
缺省函数的声明与定义
在复杂工程里把某些函数声明单独封装到头文件里应该是个常识,不过在缺省函数里声明定义分离是个大坑,举个例子:

你要是这么写,直接报错

(⊙o⊙)…为什么不能这么写,你看看下面这张图。

wow,声明和定义居然不一样,编译器要用哪个?编译器不想搭理你还在你脸上甩了两个重定义错误。所以正确的做法是这样的:

在声明处定义缺省形参,在定义处写常规形参。至于为什么要在声明处定义,很好理解。如果在定义处定义缺省形参,那么在传参时部分传法会与声明冲突,结果就会报错

那为什么编译器可以通过缺省函数的声明找到其定义,他们看上去可不太一样,那就要用到函数重载的相关知识了。
函数重载
举个例子,上面的Add函数要完成int + int的计算和double + double的计算,在C语言里只能给函数名加修饰符来区分,至于现在,上代码。

所谓重载就是一词多义,那么重载函数指的是函数名的一词多义,这个概念应该很好理解。
如何构成函数重载
1.形参类型不同

2.形参个数不同

3.形参顺序不同

上述三个条件只需成立一个即可构成函数重载。
注意事项:1. 对于第二点,与缺省函数联用有可能出现调用歧义。


2. 对于第三点,请注意交换顺序的是形参类型,而非形参名。
3. 其他条件相同,返回值类型不同的同名函数不构成函数重载。(一旦构成函数重 载,你可以修改任意重载函数的返回值类型,并不是指返回值类型不同的同名函 数不构成函数重载)

函数重载核心原理——函数名称修饰
正儿八经学习过C语言的人应该知道,把工程里的代码转化成可执行文件分两步,编译(编译器)+ 链接(链接器),其中编译分为三步,预处理(去注释,宏替换,头文件展开,条件编译),编译(检查语法,生成汇编代码),汇编(形成符号表,生成机器码),链接阶段进行符号表的合并与重定位,合并段表。

这里我故意写了一个bug,还把文件后缀改成了.c,所以在C环境下这里被红框框起来的部分就是函数func在符号表里的样子,现在让我们用CPP环境再试一次。

尽管vs2019的函数名修饰规则很奇葩,但它至少给了一点有用信息。C++符号表里的函数名多了很多修饰符,而且在上述例子中int,double位置的交换直接导致了N,H字母位置的交换。结论很明显,C++在形成符号表的时候把形参以某种规则加入到函数名中,这样做使得重载函数在符号表中的名字变的可以区分,如此一来重载函数也能拥有独立地址,重载函数的自动匹配也就实现了。
现在我们就能回答缺省函数那里的问题了。因为函数名修饰规则不支持缺省参数,所以在符号表里缺省函数的声明与定义是一样的,那么在链接的时候链接器会自动将声明定义二合一,形成一个具有实际地址的函数,这样就不会出现链接错误了。
同理,重载函数不支持返回值重载也是因为函数名修饰规则不支持返回值,在符号表里就会出现两个一样的函数名,编译器就会爆重定义错误。
这期的干货很多,各位观众下去好好消化一下。下一期教程讲引用,难度还要再加,诸位不要掉队哦。