C++函数指针赋值时const参数的正确性疑问
我目前在大学学习C++和OOP的基础知识,对函数指针赋值的工作原理尚未完全掌握。我遇到了如下代码:
void mystery7(int a, const double b) { cout << "mystery7" << endl; } const int mystery8(int a, double b) { cout << "mystery8" << endl; } int main() { void(*p1)(int, double) = mystery7; /* 无错误! */ void(*p2)(int, const double) = mystery7; const int(*p3)(int, double) = mystery8; const int(*p4)(const int, double) = mystery8; /* 无错误! */ }我理解p2和p3的赋值是合理的,因为函数参数类型匹配且const属性正确,但为何p1和p4的赋值不会失败?将const double/int匹配到非const double/int难道不应该是非法的吗?
这问题问得很到位!其实这是C++里函数指针赋值的参数兼容性规则在起作用,核心点在于按值传递的参数,const限定不会阻碍隐式转换,咱们拆开来看:
为什么p1的赋值没问题?
mystery7的第二个参数是const double,而p1的第二个参数是double。当你通过p1调用这个函数时,你传的double实参会被隐式转换成const double——这完全合法!毕竟const double的形参只是保证函数内部不会修改这个参数的拷贝,你传个非const的实参进去,拷贝后加个const限定,一点风险都没有。C++编译器允许这种赋值,正是因为调用时的参数转换是安全的。
为什么p4的赋值也没问题?
mystery8的第一个参数是int,p4的第一个参数是const int。同样的逻辑,当你通过p4调用时,传的const int实参会被拷贝给int形参。按值传递的场景下,const实参的拷贝可以直接给非const形参——毕竟拷贝出来的变量和原实参完全独立,函数内部改这个形参也不会影响原实参,这种转换完全合法,所以编译器不会报错。
关键规则总结
只要是按值传递的参数,函数指针的参数类型和原函数的参数类型之间,const/volatile限定的差异不会导致赋值失败,只要基础类型一致就行。但如果是引用或者指针类型的参数,情况就不一样了——比如原函数参数是const int&,你要是把它赋值给int&类型的函数指针,编译器肯定报错,因为这会允许你通过指针修改原本被const保护的对象,违反了const的安全性。但你的例子里都是按值传递,所以完全不受这个限制。
内容的提问来源于stack exchange,提问作者edwardlam0328

