本周小贴士#109:在函数声明中有意义的‘const‘
Posted -飞鹤-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了本周小贴士#109:在函数声明中有意义的‘const‘相关的知识,希望对你有一定的参考价值。
作为totW#109最初发表于2016年1月14日
由Greg Miller(jgm@google.com)创作
本文档将解释什么时候在函数声明中使用const是有意义的,什么时候是无意义且最好省略。但是首先,让我们简要解释一下术语声明和定义的含义。
考虑下面的代码:
void F(int); // 1: F(int)的声明
void F(const int); // 2: F(int)的再次声明
void F(int) { /* ... */ } // 3: F(int)的定义
void F(const int) { /* ... */ } // 4: 错误:F(int)的重定义
前面两行是函数声明。函数声明是告诉编译器函数的签名和返回类型。在上面的例子中,函数签名是F(int)。函数参数类型的常量性被忽略,因此两个声明是等效的(参见“可重载声明”)
上述代码的第3行和第4行是函数定义。函数的定义也是声明,但是定义包括函数体。因此,第3行是对签名为F(int)的函数的定义。同样的,第4行也是对同一函数F(int)的定义,这将导致一个链接时错误。允许多次声明,但是仅允许一次定义。
尽管在第3行和第4行定义和声明了相同的函数,但是由于它们的声明方式,这里有一个不同在他们的函数体中。根据第3行的定义,在函数中的函数参数变量类型将为int(即非常量)。另一方面,在第4行的定义将在函数内生成一个函数参数变量,其类型为const int。
在函数声明中有意义的const
并非所有在函数声明中的const限定会被忽略。引用来自标准C++中的“可重载声明”:
在参数类型规范中的const类型指示符是非常重要的,可以用来区别重载函数声明。
下面的内容是const很重要并且不能忽略的示例:
void F(const int* x); // 1
void F(const int& x); // 2
void F(std::unique_ptr<const int> x); // 3
void F(int* x); // 4
在上面的示例中,x参数本身从来没有被声明为const。上述每个函数都接受一个名为x的不同类型的参数,从而形成一个有效的重载集。第1行声明了一个函数,该函数接受“指向const的int的指针”。第2行声明了一个函数,该函数接受“对const的int的引用”。第3行声明了一个“unqiue_ptr到const的int”的函数。所有这些const的用法都很重要并且不能忽略,因为它们是参数类型规范的一部分,并且不是会影响到参数x本身的顶级const限定。
第4行很有趣,因为它根本不包括const关键字,并且由于本文前面引用的原因,初看可能与第1行等效。这原因并不是真的,并且第4行是一个有效的且独特的声明,它的真正原因是最顶级或最外层的参数类型规范的const限定符是被忽略的。
为了完成这个示例,让我们再看几个示例,其中const没有意义并且被忽略。
void F(const int x); // 1: 声明F(int)
void F(int* const x); // 2: 声明F(int*)
void F(const int* const x); // 3: 声明F(const int*)
经验法则
尽管我们之中很少有人真正掌握C++的所有令人愉悦的细微之处,但是重要的是我们要尽最大努力去理解游戏规则。这将帮助我们编写出让其他遵循相同规则并参与相同游戏的C++程序员可以理解的代码。为此,了解const限定在函数声明中何时有意义以及何时应被忽略是很重要的。
尽管这里没有来自Google C++风格指南中的官方指导,也没有单一普遍接受的意见,但是以下是一组合理的指导方针:
- 切勿在不是定义的声明中对函数参数使用顶级const(并且注意不要复制/粘贴无意义的const)。它是无音义的,并且会被编译器忽略,它是视觉噪点,并且可能误导读者。
- 请依据你(或你的团队)的判断,对定义中的函数参数使用顶级const。你可以遵循与何时声明函数局部变量const相同的基本原理。
以上是关于本周小贴士#109:在函数声明中有意义的‘const‘的主要内容,如果未能解决你的问题,请参考以下文章