重载的编程语言中的重载
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重载的编程语言中的重载相关的知识,希望对你有一定的参考价值。
参考技术A编程中重载的定义:函数名相同,函数的参数列表不同(包括参数个数和参数类型),至于返回类型可同可不同。
重载是可使函数、运算符等处理不同类型数据或接受不同个数的参数的一种方法,关于重载一词在词义上有两种不同的说法: 重载是一种多态(如C++,Java),有四种形式的多态:
1.虚函数多态
2模板多态
3重载
4转换
所谓的动态和静态区分是另一种基于绑定时间的多态分类,严格来说,重载是编译时多态,即静态多态,根据不同类型函数编译时会产生不同的名字如int_foo和char_foo等等,以此来区别调用。故重载仍符合多态定义——通过单一标识支持不同特定行为的能力,只是重载属于静态多态,而不是通过继承和虚函数实现的动态多态。 重载(overloaded)和多态无关,真正和多态相关的是覆盖(inheritance)。
当派生类重新定义了基类的虚拟方法后,基类根据赋给它的不同的派生类引用,动态地调用属于派生类的对应方法,这样的方法调用在编译期间是无法确定的。因此,这样的方法地址是在运行期绑定的(动态绑定)。
重载只是一种语言特性,是一种语法规则,与多态无关,与面向对象也无关。
不过针对所谓的第二种重载,有一个专门的名词--重写或重定义。重载与重写的区别就在于是否覆盖,重写一般多发生在不同的类且存在继承关系之间,而重载多是在一个类里或者一块代码段里。
特点:
由于重载可以在同一个类中定义功能类似的函数,这给程序员管理类的相似函数提供了极大的方便。例如,在一个定义圆的类中,需要设定圆心和半径来确定一个圆对象,程序员不需要设定setRadius(float r)和SetPoint(float x,float y)两个不同名函数,而只需要设定一个CSetCicle函数名就够了。在这个简单的例子中重载并没有明显的优势,可是当一个类中相似功能函数有几十、上百个的时候,重载的优势就显现出来了,这时程序员不需要去记这么繁多的函数名,可以把更多的精力放在程序本身上。重载的方法只属于子类。
函数:
1.函数名必须相同,返回值可以相同,也可以不同,但是特征标必须不同。是函数名来确定函数的不同,是特征标是函数可以重载。编译器首先选在函数名,然后再根据特征标在众多重载的函数中找到合适的。
2.匹配函数时,编译器将不区分类型引用和类型本身,也不区分const和非const变量。(小注:因为这些在定义和声明时可能不同,但是在调用时都是一样的,编译器将无法区分)。但是值得注意的是,形参与const形参的等价性仅适于非引用形参。有const引用形参的函数与有非const引用形参的函数是不同的。类似的,如果函数带有指向const类型的指针形参,则与带有指向相同类型的非const对象的指针形参的函数不相同。
3.名称修饰(name decoration)。编译器将根据原型中指定的形参对每个函数名进行加密。
重定义:
被重载的函数有不同版本,这些函数地位是一样的,可以根据特征标的不同选择不同的函数。被重定义的函数也有不同的版本,但是你不能随意选择,你只能选择最新的版本,被重定义多发生在类之间的继承里。
4.函数会有那么多版本,那么编译将选哪一个呢。当然,理想情况是,实参与形参的数据类型完全匹配,但是当不完全匹配时会怎样呢?这就要牵扯到c++里复杂的类型转换了。
在重载及函数模板重载里,编译器选择函数,要经过以下三步,这个过程称为重载解析。
第一步:创建候选函数列表,其中包含有与被调函数名称相同的函数与模板函数。
第二步:使用候选函数列表创建可行函数列表。这些都是参数数目正确的函数。
第三步:确定是否有最佳可行的函数。如果有,则使用。
确定最佳函数,只考虑其特征标,而不考虑返回类型(也无从考虑,但是要是硬想办法的话,也有,不过没有必要为了不必要的性能而浪费资源)。确定最佳函数,匹配特征标要依次经过以下判断:(1)完全匹配(常规函数优于模板;允许无关紧要的转换)(2)提升匹配(如char和short自动转换为int)(3)标准转换(int转换为char,long转换为double)(4)用户自定义的转换(如类声明中定义的转换函数)。
完全允许无关紧要的转换,这些转换包括引用,指针与实体之间,数组与指针之间,函数与函数指针之间,const与非const等等。
其次还要注意匹配的优先级。1,指向非const数据的指针和引用优先于const的指针和引用参数匹配(这种优先级只有当指针或引用出现时产生)。2,非模板函数,优于模板函数,显示具体化的模板将优于隐式具体化的模板,总之较具体的优先(注意,具体并不是由于显隐决定的,术语“最具体”是指编译器推断使用哪种类型时执行的转换最少)。 通常,派生类继承基类的方法,因此,在调用对象继承方法的时候,调用和执行的是基类的实现.但是,有时需要对派生类中的继承方法有不同的实现.
例如,假设动物类存在跑的方法,从中派生出马和狗,马和狗的跑得形态是各不相同的,因此同样方法需要两种不同的实现,这就需要重新编写基类中的方法.
重写基类方法就是修改它的实现或者说在派生类中重新编写 //java代码//方法重写public class Fatherpublic void ovel(int i)/*do something...*/public String ovef()/*do something...*/return ***;public class Son extends Fatherpublic void ovel(int i)/*do other something...*/public String ovef()/*do other something...*/return XXX;
29 类中的函数重载
1. 函数重载的回顾-----同一个函数名定义不同函数(互不相同的函数,共享一个函数名)
(1)函数重载的本质为相互独立的不同函数
(2)C++中通过函数名和函数参数确定函数调用,函数名和参数列表组成唯一的标识
(3)无法直接通过函数名得到重载函数的入口地址-------重载函数的入口地址不同
(4)函数重载必然发生在同一个作用域
【编程实验】类成员函数指针
#include <iostream> using namespace std; class Test { public: void show() { cout <<"Test::show()" << endl; } void print() { cout <<"Test::print()" << endl; } }; //声明类成员函数指针 typedef void (Test::* PFunc)(); int main() { Test t; PFunc p = t.show; (t.*p)(); //Test::show() p = t.print; (t.*p)(); //Test::print() }
2. 类中的函数重载
——类中成员函数可以进行重载-------关键:注意考虑在同一个作用域
-
构造函数的重载
-
普通成员函数的重载
-
静态成员函数的重载
全局函数、普通成员函数、静态成员函数能不能构成函数重载???
1 #include<stdio.h> 2 3 class Test 4 { 5 int i; 6 public: 7 8 Test() //无参构造函数 9 { 10 printf("Test::Test() "); 11 this->i = 0; 12 } 13 Test(int i) //含参构造函数 14 { 15 printf("Test::Test(int i) "); 16 this->i = 0; 17 } 18 Test(const Test& obj) //拷贝构造函数 19 { 20 printf("Test::Test(const Test& obj) "); 21 this->i = obj.i; 22 } 23 24 static void func() //不含参静态成员函数 调用的时候使用类名Test::func(); 25 { 26 printf("void Test::func() "); 27 } 28 void func(int i) //含参成员函数--普通成员函数,调用的时候使用对象t1.func(2) 29 { 30 printf("void Test::func(int i),i=%d ",i); 31 } 32 int getI() 33 { 34 return i; 35 } 36 }; 37 38 //全局函数void func() 和不含参成员函数static void func() 作用域不同 不属于重载函数 39 40 void func() //无参全局函数-----全局函数位于全局命名空间 41 { 42 printf("void func() "); 43 } 44 void func(int i) // 带参全局函数 45 { 46 printf("void func(int i),i=%d ", i); 47 } 48 49 int main() 50 { 51 //使用函数名和参数列表能确定唯一调用哪个函数 52 53 func(); //调用无参全局函数 void func() 54 func(1); //调用 带参全局函数 void func(int i),i=1 55 56 Test t; //调用类内无参构造函数 Test::Test() 57 Test t1(1); //调用类内带参构造函数 Test::Test(int i) 58 Test t2(t1); //用t1对象去初始化t2 调用类内拷贝构造函数 Test::Test(const Test& obj) 59 //等价于Test t2 = t1; 60 61 62 func(); //调用无参全局函数 void func() 63 Test::func(); //调用类内含参成员函数 void Test::func() 64 65 func(2); //调用带参全局函数 void func(int i),i=2 66 t1.func(2); //调用类内含参成员函数 void Test::func(int i),i=2 67 t1.func(); //调用类内含参成员函数 void Test::func() 68 69 //func(2)属于类内普通成员函数,通过对象直接调用 70 //func()属于类内静态成员函数 ,类名和对象调用 71 72 return 0; 73 }
3. 重载的深度意义
(1)通过函数名对函数功能进行提示
(2)通过参数列表对函数用法进行提示
(3)扩展系统中已经存在的函数功能
(4)扩展其他更多的功能
存在问题:
1 #include<stdio.h> 2 #include<string.h> 3 4 //重载意义分析 5 6 int main() 7 { 8 const char* s = "i.love.you"; //设置字符串 9 char buf[16] = { 0 }; //将字符串s拷贝到buffer先初始化为0 10 11 //strcpy_s(buf, s); //存在问题-------若buf大小设置不够,就是发生内存越界 char buf[8] = { 0 }; 会产生bug 12 13 //怎么处理? 14 strncpy(buf, s, sizeof(buf) - 1); //将拷贝大小最多设置为sizeof(buf) - 1 15 //但是这样增加了一个函数,strncpy还不好记 16 17 printf("%s ", buf); 18 19 return 0; 20 } 21 22 接下来通过函数重载扩展strncpy------将之前的strcpy_s扩展为三个参数
重载之后:
1 #include<stdio.h> 2 #include<string.h> 3 4 5 char* strcpy(char* buf, const char* str, unsigned int n) //重载函数 6 { 7 return strncpy(buf, str, n); 8 } 9 10 int main() 11 { 12 const char* s = "i.love.you"; //设置字符串 13 char buf[16] = { 0 }; //将字符串拷贝到buffer先初始化为0 14 //若buf大小设置不够,就是发生内存越界 char buf[8] = { 0 }; 会产生bug 15 16 // strcpy(buf, s); 17 strcpy(buf, s, sizeof(buf) - 1); //使用函数重载扩展了strcpy_s的功能 两个参数变成三个参数 18 19 printf("%s ", buf); 20 21 return 0; 22 }
4. 小结
(1)类的成员函数之间可以重载
(2)重载必须发生在同一个作用域中(全局函数和成员函数不能构成重载关系)
(3)重载的意义在于扩展已经存在的功能
以上是关于重载的编程语言中的重载的主要内容,如果未能解决你的问题,请参考以下文章