学科分类
目录
C++基础

重载函数

在平时生活中经常会出现这样一种情况,一个班里同时可能同时有两个叫小明的同学,甚至有多个,但是他们的身高、体重、性别、外貌等会有所不同,老师点名字时都会根据他们的特征来区分,如高个小明,胖小明等。其实在编程语言里也会存在这种情况,几个不同的函数有着相同的名字,在调用时根据参数的不同确定调用哪个函数,这就是C++提供的函数重载机制。

所谓重载(overload)函数就是在同一个作用域内几个函数名字相同但形参列表不同。例如在同一个作用域内同时定义几个add()函数。

void add(int x, int y);
void add(float x);
double add(double x, double y);

这几个就是重载函数,它们函数名相同但参数列表却不相同,参数列表的不同有三种含义:参数个数不同,或者参数类型不同或者参数个数和类型都不同。

为了加深读者的理解,我们用一个案例来调用这几个重载函数,如例1所示。

例1

 1    #include <iostream>
 2    using namespace std;
 3    void add(int x, int y)
 4    {
 5        cout << "int: " << x + y << endl;
 6    }
 7    void add(float x)
 8    {
 9        cout << "float: " << 10 + x << endl;
 10    }
 11    double add(double x, double y)
 12    {
 13        return x + y;
 14    }
 15    int main()
 16    {
 17        add(10.2);  //一个实型参数
 18        add(1, 3);  //两个整型参数
 19        cout << add(3.2, 2.3) << endl;  //两个实型参数
 20        system("pause");
 21        return 0;
 22    }

运行结果如图1所示。

图1 例1运行结果

从图1可以看出,三次调用add()函数,传入不同的参数就调用了对应的函数,在这个过程中,编译器会根据传入的实参与几个重载函数逐一匹配,然后根据比较结果决定到底调用哪个函数。

注意:重载函数不能以返回值来区分不同。

当重载函数中的形参都是普通形参,定义和调用一般不会出现问题,但是当形参由const修饰或者有默认参数值时,有一些问题需要注意,接下来我们就分别来学习一下这两种情况。

1、重载与const形参

如果是底层的const形参,即const修饰的是指针指向的变量,则通过区分其指向的是常量对象还是非常量对象可以实现函数重载,例如下面两对函数:

void func1(int *x);              //普通指针
void func1(const int*x);         //常量指针
void func2(int &x);             //普通引用
void func2(const int &x);         //常引用

上面的两对重载函数,编译器可以通过实参是否是常量来推断应该调用哪个函数。对于const对象,因为const对象不能转换成其他类型,所以只能把const对象传递给const形参;而对于非const对象,因为非const对象可以传递给const形参,所以上面函数都可以被非const对象调用,但是在重载函数中,编译器会优先选择非常量版本的函数。

接下来通过一个案例来加深读者对重载函数中const形参的印象,如例2所示。

例2

 1    #include <iostream>
 2    using namespace std;
 3    void func1(const int *x) //常量指针
 4    {
 5        cout << "const int*: " << *x  << endl;
 6    }
 7    void func1(int *x) //普通指针
 8    {
 9        cout << "int*: " << *x << endl;
 10    }
 11    void func2(const int &x) //常引用
 12    {
 13        cout << "const int&: " << x << endl;
 14    }
 15    void func2(int &x) //普通引用
 16    {
 17        cout << "int&: " << x << endl;
 18    }
 19    int main()
 20    {
 21        const int a = 1;
 22        int b = 2;
 23        func1(&a); //常量参数
 24        func1(&b); //非常量参数
 25    
 26        func2(a);  //常量参数
 27        func2(b);  //非常量参数
 28        system("pause");
 29        return 0;
 30    }

运行结果如图2所示。

图2 例2运行结果

由图2可以看出,当传入常量对象参数时会调用const形参函数,当传入非常量对象时,则优先调用了非const形参函数。

但如果是顶层的const形参,即const修饰的是指针本身,则无法和另一个没有顶层const的形参区分开来,对于const修饰形参变量,则只是不能在函数内部改变变量的值,并不一定要求传入进来的变量就得是常量;对于const修饰指针,只是保证这个指针不指向别的变量而已,而不要求它指向的变量是常量。例如下面的函数:

void func1(int x);
void func1(const int x); //函数func1()重复声明
void func2(int *x);
void func2(int * const x); //函数func2()重复声明

这两对函数,第二个函数都是对第一个函数的重复声明,因为顶层const不影响传入函数的对象,所以无法以顶层const形参来定义重载函数。

2、重载和默认参数

当使用具有默认参数的函数重载形式时须注意防止调用的二义性,例如下面的两个函数:

int add(int x, int y = 1);
void add(int x);

当有如下函数调用时就会产生歧义:add(10);它既可以调用第一个add()函数也可以调用第二个add()函数,编译器无法确认到底要调用哪个重载函数,这就产生了调用的二义性。在使用时要注意这种情况的发生。

点击此处
隐藏目录