请注意以下C ++代码:
#include <iostream>
using std::cout;
int foo (const int);
int main ()
{
cout << foo(3);
}
int foo (int a)
{
a++;
return a;
}
请注意foo()
的原型需要const int
,定义需要int
。这个编译没有任何错误......
为什么没有编译错误?
答案 0 :(得分:33)
因为foo
函数的调用者无论foo
是否修改其变量副本都无关紧要。
特别是在C ++ 03标准中,以下2个片段解释了原因:
C ++ 03 Section:13.2-1
如果两个函数声明属于同一范围,则它们引用相同的函数 具有等效的参数声明(13.1)。
C ++ 03 Section:13.1-3
仅在const和/或volatile存在与否的情况下不同的参数声明是等效的。仅以这种方式忽略参数类型规范最外层的const和volatile类型说明符;埋在参数类型规范中的const和volatile类型说明符很重要,可用于区分重载的函数声明。
答案 1 :(得分:13)
顶级const
(即,适用于传递的值,而不是它指向或引用的值)仅影响函数的实现,而不影响接口。编译器从接口角度(即调用端)忽略它,并仅在实现上强制执行它(即函数体中的代码)。
答案 2 :(得分:2)
正如其他人所解释的那样,标准说它没关系,并且编译器可以宽容地执行此操作,因为它不会影响调用者,但是没有人回答为什么编译器应该选择宽松。一般来说,它并不是特别宽松,只是一直看着界面然后潜入实现的程序员可能会在它的脑海中有一个参数是const,当它不是,反之亦然 - 这不是一件好事。
这种宽容允许实现更改而无需修改标头,这使用传统的make工具触发客户端代码的重新编译。这在企业规模开发中可能是一个严重的问题,低级标题(例如日志记录)中的非实质性更改可能会强制重建它与应用程序之间的几乎所有对象...浪费数千小时的CPU时间和推迟所有人和等待构建的一切。
所以,这很难看,但却是一种实际的让步。
我还回答了另一个类似的问题,该问题探讨了为什么不允许重载f(const T)和f(T)的问题 - 阅读此内容的任何人都可能感兴趣 - Top-level const doesn't influence a function signature
答案 3 :(得分:-2)
int foo (const int a)
{
a++;
return a;
}
这会在编译期间抛出错误。