函数可以被多次不能被重载的函数吗

2015年2月 Java大版内专家分月排行榜第二2014年3月 Java大版内专家分月排行榜第二
2014年9月 Java大版内专家分月排行榜第三2014年6月 Java大版内专家分月排行榜第三2014年2月 Java大版内专家分月排行榜第三2013年11月 Java大版内专家分月排行榜第三2013年10月 Java大版内专家分月排行榜第三
2011年 总版技术专家分年内排行榜第三2010年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第五
本帖子已过去太久远了,不再提供回复功能。可重入函数
可重入函数主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。
可重入函数也可以这样理解,重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外不依赖于任何环境(包括static),这样的函数就是purecode(纯代码)可重入,可以允许有该函数的多个副本在运行,由于它们使用的是分离的栈,所以不会互相干扰。如果确实需要访问全局变量(包括static),一定要注意实施互斥手段。可重入函数在并行运行环境中非常重要,但是一般要为访问全局变量付出一些性能代价。
满足下列条件的函数多数是不可重入的:
1) 函数体内使用了静态的数据结构;
2) 函数体内调用了malloc()或者free()函数;
3) 函数体内调用了标准I/O函数。
下面举例加以说明。
可重入函数
void strcpy(char *lpszDest, char *lpszSrc) {
while(*lpszDest++=*lpszSrc++);
&不可重入函数1
char cT//全局变量
void SwapChar1(char *lpcX, char *lpcY) {
cTemp=*lpcX;
*lpcX=*lpcY;
lpcY=cT//访问了全局变量
编写可重入的函数?
在函数体内不访问那些全局变量,不使用静态局部变量,坚持只使用局部变量,写出的函数就将是可重入的。如果必须访问全局变量,记住利用互斥信号量来保护全局变量。
将一个不可重入的函数改写成可重入的函数?
把一个不可重入函数变成可重入的唯一方法是用可重入规则来重写它。只要遵守了几条很容易理解的规则,那么写出来的函数就是可重入的。
1) 不要使用全局变量。因为别的代码很可能覆盖这些变量值。
2) 在和硬件发生交互的时候,切记执行类似disinterrupt()之类的操作,就是关闭硬件中断。完成交互记得打开中断,在有些系列上,这叫做“进入/退出核心”。
3) 不能调用其它任何不可重入的函数。
4) 谨慎使用堆栈。最好先在使用前先OS_ENTER_KERNAL。
堆栈操作涉及内存分配,稍不留神就会造成益出导致覆盖其他任务的数据,所以,请谨慎使用堆栈!最好别用!很多黑客程序就利用了这一点以便系统执行非法代码从而轻松获得系统控制权。还有一些规则,总之,时刻记住一句话:保证中断是安全的!
重载函数是函数的一种特殊情况,为方便使用,C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个运算符完成不同的运算功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。
两个重载函数必须在下列一个或两个方面有所区别:
1.、函数有不同参数。
2、函数有不同参数类型,
C++的这种编程机制给编程者极大的方便,不需要为功能相似、参数不同的函数选用不同的函数名,也增强了程序的可读性。
C++运算符重载的相关规定如下:
(1)不能改变运算符的优先级;
(2)不能改变运算符的结合型;
(3)默认参数不能和重载的运算符一起使用;
(4)不能改变运算符的操作数的个数;
(5)不能创建新的运算符,只有已有运算符可以被重载;
(6)运算符作用于C++内部提供的数据类型时,原来含义保持不变。
& & 重载函数(overloaded function)是C++支持的一种特殊函数,C++编译器对函数重载的判断更是C++语言中最复杂的内容之一
& & 重载函数的定义:在相同的声明域中的函数名相同的,而参数表不同的,即通过函数的参数表而唯一标识并且来区分函数的一种特殊的函数。
& & 函数为什么要重载呢?何时应该选择函数重载(function overloading)?
& & 函数的重载其实就是“一物多用”的思想(这里指的“物”是“函数名”),其实不仅是函数可以重载,运算符也是可以重载的。
例如:运算符“&&”和“&&”既可以作为移位运算符,有可以作为输出流中的插入运算符和输入流中的提取运算符。
当将要定义一组函数,使它们执行一系列的操作,但是它们是应用在不同的参数类型上的。此时我们可以选择重载函数。
例如: int z_x_max (int,int); //返回两个整数的最大值;
int ve_max (const vector &int& &); //返回vector容器中的最大值;
int matrix_max (const matrix &); //返回matrix引用的最大值;
上面的三个函数都可以大概地说成判断一组数中的最大值,对于函数的用户来说,他们并不关心函数定义的细节,也就是说他们不关心判断两个整数的大小和判断数组(vector容器)数的大小应该使用不同的函数,而对于程序的设计者来说这可是不得不想到的。程序员必须记住并查找每个函数名。而函数的重载把程序员从这种问题的复杂性中解放了出来,C++提供了这种支持。
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:28199次
排名:千里之外
原创:42篇
转载:21篇
(1)(1)(10)(13)(38)【图文】5.重载_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
上传于|0|0|暂无简介
大小:187.66KB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢什么是函数重载?为什么使用函数重载?C++中如何实现函数重载?
发布日期: 10:58
C++函数重载
本章我们主要学习什么是函数重载?为什么使用函数重载?C++中如何实现函数重载?下面我们就做一下具体讲解,希望大家多多支持中国站长网络学院。
什么是函数重载(what)?函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。When two or more different declarations are specified for a single name in the same scope, &that name is said to overloaded. &By extension, two declarations in the same scope that declare the same name but with different types are called overloaded declarations. Only function declaratio object and type declarations cannot be overloaded. ——摘自《ANSI C++ Standard. P290》看下面的一个例子,来体会一下:实现一个打印函数,既可以打印int型、也可以打印字符串型。在C++中,我们可以这样做:#include&iostream&void print(int i){& & & & cout&&&print a integer :&&&i&&}void print(string str){& & & & cout&&&print a string :&&&str&&}int main(){& & & & print(12);& & & & print(&hello world!&);& & & & return 0;}通过上面代码的实现,可以根据具体的print()的参数去调用print(int)还是print(string)。上面print(12)会去调用print(int),print(&hello world&)会去调用print(string),如下面的结果:(先用g++ test.c编译,然后执行)为什么需要函数重载(why)?试想如果没有函数重载机制,如在C中,你必须要这样去做:为这个print函数取不同的名字,如print_int、print_string。这里还只是两个的情况,如果是很多个的话,就需要为实现同一个功能的函数取很多个名字,如加入打印long型、char*、各种类型的数组等等。这样做很不友好!类的构造函数跟类名相同,也就是说:构造函数都同名。如果没有函数重载机制,要想实例化不同的对象,那是相当的麻烦!操作符重载,本质上就是函数重载,它大大丰富了已有操作符的含义,方便使用,如+可用于连接字符串等!通过上面的介绍我们对函数重载,应该唤醒了我们对函数重载的大概记忆。下面我们就来分析,C++是如何实现函数重载机制的。编译器如何解决命名冲突的?为了了解编译器是如何处理这些重载函数的,我们反编译下上面我们生成的执行文件,看下汇编代码(全文都是在Linux下面做的实验,Windows类似,你也可以参考《一道简单的题目引发的思考》一文,那里既用到Linux下面的反汇编和Windows下面的反汇编,并注明了Linux和Windows汇编语言的区别)。我们执行命令objdump -d a.out &log.txt反汇编并将结果重定向到log.txt文件中,然后分析log.txt文件。发现函数void print(int i) 编译之后为:(注意它的函数签名变为——_Z5printi)发现函数void print(string str) 编译之后为:(注意它的函数签名变为——_Z5printSs)我们可以发现编译之后,重载函数的名字变了不再都是print!这样不存在命名冲突的问题了,但又有新的问题了——变名机制是怎样的,即如何将一个重载函数的签名映射到一个新的标识?我的第一反应是:函数名+参数列表,因为函数重载取决于参数的类型、个数,而跟返回类型无关。但看下面的映射关系:void print(int i) & & & & & & & & & &--& & & & & _Z5printivoid print(string str) & & & & --& & & & & _Z5printSs进一步猜想,前面的Z5表示返回值类型,print函数名,i表示整型int,Ss表示字符串string,即映射为返回类型+函数名+参数列表。最后在main函数中就是通过_Z5printi、_Z5printSs来调用对应的函数的:80489bc: & & & e8 73 ff ff ff & & & & &call & 8048934 &_Z5printi&……………80489f0: & & & e8 7a ff ff ff & & & & &call & 804896f &_Z5printSs&我们再写几个重载函数来验证一下猜想,如:void print(long l) & & & & & --& & & & & & _Z5printlvoid print(char str) & & &--& & & & & & _Z5printc可以发现大概是int-&i,long-&l,char-&c,string-&Ss….基本上都是用首字母代表,现在我们来现在一个函数的返回值类型是否真的对函数变名有影响,如:#include&iostream&int max(int a,int b){& & & & return a&=b?a:b;}double max(double a,double b){& & & & return a&=b?a:b;}int main(){& & & & cout&&&max int is: &&&max(1,3)&&& & & & cout&&&max double is: &&&max(1.2,1.3)&&& & & & return 0;}int max(int a,int b) 映射为_Z3maxii、double max(double a,double b) 映射为_Z3maxdd,这证实了我的猜想,Z后面的数字代码各种返回类型。更加详细的对应关系,如那个数字对应那个返回类型,哪个字符代表哪重参数类型,就不去具体研究了,因为这个东西跟编译器有关,上面的研究都是基于g++编译器,如果用的是vs编译器的话,对应关系跟这个肯定不一样。但是规则是一样的:“返回类型+函数名+参数列表”。既然返回类型也考虑到映射机制中,这样不同的返回类型映射之后的函数名肯定不一样了,但为什么不将函数返回类型考虑到函数重载中呢?——这是为了保持解析操作符或函数调用时,独立于上下文(不依赖于上下文),看下面的例子float sqrt(float);double sqrt(double);void f(double da, float fla){& & & float fl=sqrt(da);//调用sqrt(double)& & & double d=sqrt(da);//调用sqrt(double)& & & fl=sqrt(fla);//调用sqrt(float)& &d=sqrt(fla);//调用sqrt(float)}如果返回类型考虑到函数重载中,这样将不可能再独立于上下文决定调用哪个函数。至此似乎已经完全分析清楚了,但我们还漏了函数重载的重要限定——作用域。上面我们介绍的函数重载都是全局函数,下面我们来看一下一个类中的函数重载,用类的对象调用print函数,并根据实参调用不同的函数:#include&iostream&class test{public:& & & & void print(int i)& & & & {& & & & & & & & cout&&&int&&&& & & & }& & & & void print(char c)& & & & {& & & & & & & & cout&&&char&&&& & & & }};int main(){& & & && & & & t.print(1);& & & & t.print('a');& & & & return 0;}我们现在再来看一下这时print函数映射之后的函数名:void print(int i) & & & & & & & & & &--& & & & & & &_ZN4test5printEivoid print(char c) & & & & & & & --& & & & & & &_ZN4test5printEc注意前面的N4test,我们可以很容易猜到应该表示作用域,N4可能为命名空间、test类名等等。这说明最准确的映射机制为:作用域+返回类型+函数名+参数列表重载函数的调用匹配现在已经解决了重载函数命名冲突的问题,在定义完重载函数之后,用函数名调用的时候是如何去解析的?为了估计哪个重载函数最适合,需要依次按照下列规则来判断:1)精确匹配:参数匹配而不做转换,或者只是做微不足道的转换,如数组名到指针、函数名到指向函数的指针、T到const T;2)提升匹配:即整数提升(如bool 到 int、char到int、short 到int),float到double3)使用标准转换匹配:如int 到double、double到int、double到long double、Derived*到Base*、T*到void*、int到unsigned int;4)使用用户自定义匹配;5)使用省略号匹配:类似printf中省略号参数如果在最高层有多个匹配函数找到,调用将被拒绝(因为有歧义、模凌两可)。看下面的例子:void print(int);void print(const char*);void print(double);void print(long);void print(char);void h(char c,int i,short s, float f){& & &print(c);//精确匹配,调用print(char)& & &print(i);//精确匹配,调用print(int)& & &print(s);//整数提升,调用print(int)& & &print(f);//float到double的提升,调用print(double)& & &print('a');//精确匹配,调用print(char)& & &print(49);//精确匹配,调用print(int)& & &print(0);//精确匹配,调用print(int)& & &print(&a&);//精确匹配,调用print(const char*)}定义太少或太多的重载函数,都有可能导致模凌两可,看下面的一个例子:void f1(char);void f1(long);void f2(char*);void f2(int*);void k(int i){& & & &f1(i);//调用f1(char)? f1(long)?& & & &f2(0);//调用f2(char*)?f2(int*)?}这时侯编译器就会报错,将错误抛给用户自己来处理:通过显示类型转换来调用等等(如f2(static_cast&int *&(0),当然这样做很丑,而且你想调用别的方法时有用做转换)。上面的例子只是一个参数的情况,下面我们再来看一个两个参数的情况:int pow(int ,int);double pow(double,double);void g(){& & & &double d=pow(2.0,2)//调用pow(int(2.0),2)? pow(2.0,double(2))?}4、编译器是如何解析重载函数调用的?编译器实现调用重载函数解析机制的时候,肯定是首先找出同名的一些候选函数,然后从候选函数中找出最符合的,如果找不到就报错。下面介绍一种重载函数解析的方法:编译器在对重载函数调用进行处理时,由语法分析、C++文法、符号表、抽象语法树交互处理,交互图大致如下:这个四个解析步骤所做的事情大致如下:1)由匹配文法中的函数调用,获取函数名;2)获得函数各参数表达式类型;3)语法分析器查找重载函数,符号表内部经过重载解析返回最佳的函数4)语法分析器创建抽象语法树,将符号表中存储的最佳函数绑定到抽象语法树上下面我们重点解释一下重载解析,重载解析要满足前面《3、重载函数的调用匹配》中介绍的匹配顺序和规则。重载函数解析大致可以分为三步:1)根据函数名确定候选函数集2)从候选函数集中选择可用函数集合3)从可用函数集中确定最佳函数,或由于模凌两可返回错误根据函数名确定候选函数集根据函数在同一作用域内所有同名的函数,并且要求是可见的(像private、protected、public、friend之类)。“同一作用域”也是在函数重载的定义中的一个限定,如果不在一个作用域,不能算是函数重载,如下面的代码:void f(int);void g(){& & & & void f(double);& & & & f(1); //这里调用的是f(double),而不是f(int)}即内层作用域的函数会隐藏外层的同名函数!同样的派生类的成员函数会隐藏基类的同名函数。这很好理解,变量的访问也是如此,如一个函数体内要访问全局的同名变量要用“::”限定。为了查找候选函数集,一般采用深度优选搜索算法:step1:从函数调用点开始查找,逐层作用域向外查找可见的候选函数step2:如果上一步收集的不在用户自定义命名空间中,则用到了using机制引入的命名空间中的候选函数,否则结束在收集候选函数时,如果调用函数的实参类型为非结构体类型,候选函数仅包含调用点可见的函数;如果调用函数的实参类型包括类类型对象、类类型指针、类类型引用或指向类成员的指针,候选函数为下面集合的并:(1)在调用点上可见的函数;(2)在定义该类类型的名字空间或定义该类的基类的名字空间中声明的函数;(3)该类或其基类的友元函数;下面我们来看一个例子更直观:void f();void f(int);void f(double, double = 314);names pace N{&& & void f(char3 ,char3);}classA{& & public: operat or double() { }};int main ( ){& & using names pace N; //using指示符& & A& & f(a);& & return 0;}根据上述方法,由于实参是类类型的对象,候选函数的收集分为3步:(1)从函数调用所在的main函数作用域内开始查找函数f的声明, 结果未找到。到main函数作用域的外层作用域查找,此时在全局作用域找到3个函数f的声明,将它们放入候选集合;(2)到using指示符所指向的命名空间 N中收集f ( char3 , char3 ) ;(3)考虑2类集合。其一为定义该类类型的名字空间或定义该类的基类的名字空间中声明的函数;其二为该类或其基类的友元函数。本例中这2类集合为空。最终候选集合为上述所列的 4个函数f。确定可用函数可用的函数是指:函数参数个数匹配并且每一个参数都有隐式转换序列。(1)如果实参有m个参数,所有候选参数中,有且只有 m个参数;(2)所有候选参数中,参数个数不足m个,当前仅当参数列表中有省略号;(3)所有候选参数中,参数个数超过 m个,当前仅当第m + 1个参数以后都有缺省值。如果可用集合为空,函数调用会失败。这些规则在前面的《3、重载函数的调用匹配》中就有所体现了。4.3、确定最佳匹配函数确定可用函数之后,对可用函数集中的每一个函数,如果调用函数的实参要调用它计算优先级,最后选出优先级最高的。如对《3、重载函数的调用匹配》中介绍的匹配规则中按顺序分配权重,然后计算总的优先级,最后选出最优的函数。
(window.slotbydup = window.slotbydup || []).push({
id: '1063561',
container: s,
size: '230,230',
display: 'inlay-fix'
C++是在C语言的基础上开发的一种面向对象编程语言,应用广泛。C++支持多种编程范式 --面向对象编程、泛型编程和过程化编程。最新正式标准C++于日公布。 其编程领域众广,常用于系统开发,引擎开发等应用领域,是至今为止最受广大程序员受用的最强大编程语言之一,支持类:类、封装、重载等特性!
本教程从基础讲解了C++语言,希望对大家有所帮助,望多多支持中国站长网络学院。
免责声明:以上教程信息由会员自行搜集、整理、发布,内容的真实性、准确性和合法性由发布会员负责。站长学院对此不承担任何责任。

我要回帖

更多关于 构造函数可以被重载吗 的文章

 

随机推荐