C++ 函数重载、缺省参数

原文:函数重载、缺省参数

一、函数重载

  • 概念在同一作用域内,声明几个功能相同(或类似)的同名函数,实现功能类似但所处理数据类型不同的函数

函数重载的条件

  • 函数名必须相同
  • 函数的参数不同(参数个数不同或参数对应位置的数据类型不同)
  • 作用域必须相同
  • 函数重载与函数的返回值无关

哪些情况不构成重载、构成重载

  • 顶层const不构成重载,所以下面的两个函数不构成重载
int add(int a,int b);
int add(const int a,const int b);

 

  • 普通引用不构成重载,所以下面的两个函数不构成重载
int add(int a,int b);
int add(int& a,int& b);
  • 常量引用或者常量指针构成重载,所以下面两组函数都构成重载(因为const对象不能转换为其它类型,所以只能将const对象传递给const形参。相反,非常量对象可以传递给任何类型,所以非const对象都可以传递给下面4个函数)
int add(int* a,int* b);
int add(const int* a,const int* b);
nt add(int& a,int& b);
int add(const int& a,const int& b);
  • const函数与非const函数构成重载
int add(int a,int b);
int add(int a,int b)const;

 

函数重载与数据类型之间的关系

  • 在书写函数时,我们要确定自己的需求。如果形参的数据类型没有设置好,编译器会报错

案例一:

  • 下面的add(3.1,4.25)函数参数为double类型,调用此函数时,编译器没有找到有double类型的函数,于是就去类型转换寻找适合的函数,发送double可以转换为int,也可以转换为float。于是产生二义性,程序报错
  • 但是可以通过在数字后面给出F或者强制类型转换来告诉编译器具体调用哪一个函数
int add(int a,int b);
float add(float a,float b);
 
int main()
{
    add(1,2);
    add(3.1,4.25);//报错
    
    add(3.1F, 4.25F);//正确
    add((float)3.1,(float)4.25);//正确
}
  • 例如:下面的3.14会转换为float也会转换为long,因此也报错
int func(long a);
int func(float a);
 
int main()
{
    func(3.14);//报错
}

 

案例二:

下面的func函数调用也会产生二义性

  • 第一步:调用func时,参数1为int,此时func去匹配两个重载函数,发现int func(int a,int b);比较合适,于是就调用此函数
  • 第二步:匹配到参数2时,3.14为double类型,编译器发现int func(double a,double b);比较合适,于是就调用此函数
  • 最后,编译器产生二义性报错
int func(int a,int b);
int func(double a,double b);
 
int main()
{
    func(1, 3.14); //报错
}

 

案例三:

常量形参与非常量形参的调用(上面,介绍过常量形参与非常量形参形成重载)

  • 执行func(a);时,因为a为非常量,因此两个函数都可以调用。但是因为把非常量赋值给常量需要强制类型转换,因此就调用int func(int &s);
  • 执行func(b);时,传入的b是const类型,因此不能把普通引用绑定到const对象上,所以只调用int func(const int &s);
  • 常量指针的原理也是如此(详情见const讲解文章)
int func(int &s);
int func(const int &s);
 
int main()
{
    int a = 10;
    const int b = 20;
    func(a); //调用int func(int &s);
    func(b); //调用int func(const int &s);
}

 

函数重载示例代码 

struct myPoint 
{
	int row, col;
};
 
myPoint add(myPoint a, myPoint b)
{
	myPoint tempPoint;
	tempPoint.col = a.col + b.col;
	tempPoint.row = a.row + b.row;
	return tempPoint;
}
int add(int a, int b)
{
	return a + b;
}
double add(double a, double b)
{
	return a + b;
}
 
int main()
{
	cout << add(1, 2) << endl;  //3
	cout << add(2.5,3.1) << endl; //5.6
	return 0;
}

函数重载与作用域的关系

  • 下面的代码不规范(不应该在一个函数中声明一个函数)。但是只是为了函数重载与作用域的关系
string read();
void print(const string&);
void print(double);
 
int main()
{
    bool read = false;
    int val = 1;
    
    string s = read(); //错误,read函数与局部变量read冲突
	
    void print(int);  //定义一个参数为int的print函数
    print("Value");  //错误,print(const string&);被隐藏
    print(val);    //正确,调用print(int)
    print(3.14);   //正确,调用print(int)
}

 

const_cast与重载

  • 现在我们有下面一个这样的函数,其中参数与返回值都是const类型的
//比较两个string对象的长度,返回较短的那个引用
const string &shortString(const string &s1, const string &s2)
{
    return s1.size() <= s2.size() ? s1 : s2;
}
  • 如果我们将两个非const string对象传递给这个函数,那么返回的仍然是const string的引用
  • 因此,我们希望有一种新的函数,当传入给它的实参不是const时,也得到一个非const对象的引用,那么使用const_cast可以做到这一点:
//比较两个string对象的长度,返回较短的那个引用
const string &shortString(const string &s1, const string &s2)
{
    return s1.size() <= s2.size() ? s1 : s2;
}
 
string &shortString(string &s1, string &s2)
{
    //调用const string&类型的shortString
    auto &r = shortString(const_cast<const string&>(s1),
        ·const_cast<const string&>(s2));
    
    //然后将返回的结果去掉const性质
    return const_cast<string&>(r);
}

缺省参数(默认实参)

  • 概念人为的为函数定义一个或多个默认参数,在调用函数时,它们被赋予一个相同的值

注意事项:

  • 如果函数没有声明,则默认形参直接写在函数定义时
  • 如果函数有声明和定义,则默认形参只可写在函数声明中,函数定义时不可以写
  • 默认形参只能写在最后,或其及其后面都是默认形参
  • 缺省参数是在编译阶段决定的,所以只能用常量或者全局变量作为缺省参数
  • 函数调用时给出实参,会覆盖掉默认参数

缺省参数示例代码

int add(int a, int b,int c=10)
{
	return a + b+c;
}
 
int main()
{
	cout << add(1, 2) << endl;  //13
	cout << add(1,2,50) << endl; //53
	return 0;

 

使用全局变量初始化缺省参数

  • 缺省参数可以使用一个函数外的变量/常量初始化。但是不能用函数内的局部变量初始化
int a=10;
int b=20;
char c='a';
void func(int num1=a,int num2=b,char s=c);
  • 注意事项:虽然可以用全局变量初始化缺省参数,但是如果全局变量被改变了,再次调用这个函数缺省参数的值也会改变
int a=10;
int b=20;
char c='a';
void func2()
{
    a=66; //改变全局变量
    int b=30; //局部变量,但是不影响全局变量
    func(); //调用func(66,20,'a');
}

 

函数的调用

  • 原理:使用的函数逐个入栈,main函数中调用到某函数时,跳到栈对应的函数位置,并返回结果
  • 普通函数的调用与内联函数的内存模型

函数重载冲突

  • 函数重载与缺省参数冲突的特殊情况
int add(int a, int b,int c=10)
{
	return a + b+c;
}
int add(int a, int b)
{
	return a + b;
}
 
int main()
{
	cout << add(1, 2) << endl;//报错,对函数的调用不明确
	return 0;
}

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值