赞
踩
省流党:const
如果修饰 指针本身,不构成重载;如果修饰 指针的指向 或 引用的实体,则构成重载。
正文如下。
我们知道,函数重载要求形参列表不同。有些场景我们可以一眼看出来是否重载,比如形参数量不同、形参类型明显不同(char和double)。但是,下面这些场景呢?
void func(int n) {}
void func(const int cn) {}
void func(int* pn) {}
void func(int* const cpn) {}
void func(int* pn) {}
void func(const int* pcn) {}
void func(int n) {}
void func(int& rn) {}
void func(int& n) {}
void func(const int& crn) {}
答案是,前两组不构成重载,后三组构成重载。
归根究底,不构成函数重载是因为出现了二义性。对于你的传参,编译器有多个选择,无法确定被调用的函数。
以第一组为例,一个int变量,我传给void func(int n);
和void func(const int cn);
都没毛病。究其根本,是因为此处是传值调用。
形参只是实参的一份拷贝,两者除了存储数据一致,没有任何联系。形参列表中的const
,是限制形参在func内的行为(只可读不可写),这和实参毫无关系。实参不知道,也无需知道func内要发生什么。_实参的任务就是提供形参拷贝的数据。虽然两者的数据是完全一致的,_但形参接受实参数据时,会忽略实参本身的特性,按照形参列表重新设计自己的特性(只读还是可读可写)。就像是你抄同学的作业,虽然你们的答案一模一样,但你可以做自己的处理,比如把变量名改一下。有可能你会选择直接CV,但这只是因为你懒。你抄作业时是有权限稍作改动,让它看起来和你抄的原版不一样。
第二组也是同理。第二个函数的const
修饰的是pointer
,意指这个指针本身不可修改。这同样也是限制形参在func内的行为。
其实这里也可以理解为是传值调用,因为形参只是将实参存储的地址拷贝了一份,但两者的行为可以全然不同(一个只读,一个可读可写)。实参只是将它存储的数据传递给了实参。之所以说形参的改变可以作用于实参,是由于pointer
存储的数据是地址,所以形参解引用也能找到实参指向的变量(这里不用过于纠结,意会就好)。
对于这两组的情况,也就是**const**
修饰变量本身,只要实参形参类型一致,实参就可以为形参提供数。甚至类型不一致,允许发生转换也是可以的。因此,编译器不能做出区分,不构成重载。
与之相对,第三组的const
修饰的是pointer
指向的int
。此时,const
限制的是指针指向的内容。两个形参都是可读可写的普通指针,但它们指向的变量一个只读,一个可读可写。实参和形参不再是毫无关联的。形参接受实参提供的数据时,不仅仅进行拷贝,还要保证自己不会对指向的内容做任何改动。就像是你去抄学霸的代码,有些东西可以自主改动,但有些是不能改的。比方说,你不能随便把public改成private,改了就错了。
在这种情况下,无论是给int*
传const int*
,还是给const int*
传int*
,都会出现权限问题。只有对应传参才合法。编译器可以找到唯一的函数,因此构成函数重载。
第五组也是类似的。引用的底层是指针,可以理解为是int * const
类型。这也是为什么第四组构成重载。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。