你用const能做到什么程度?你只是在必要的时候才把函数变成const,还是从头到尾到处都用它?例如,想象一个简单的变异子,它接受一个布尔参数:

void SetValue(const bool b) { my_val_ = b; }

这个const真的有用吗?就我个人而言,我选择广泛地使用它,包括参数,但在这种情况下,我想知道它是否值得?

我还惊讶地发现,你可以在函数声明中的形参中省略const,但可以在函数定义中包含它,例如:

. h文件

void func(int n, long l);

. cpp文件

void func(const int n, const long l)

这有什么原因吗?这对我来说有点不寻常。


当前回答

原因是形参的const只在函数内局部应用,因为它处理的是数据的副本。这意味着函数签名实际上是相同的。不过,经常这样做可能是不好的风格。

我个人倾向于不使用const,除了引用和指针形参。对于复制的对象来说,这并不重要,尽管它可以更安全,因为它表明了函数中的意图。这真的是一个主观判断。我倾向于使用const_iterator,但当循环某些东西时,我不打算修改它,所以我猜每个人都有自己的,只要严格维护引用类型的const正确性。

其他回答

确实没有理由将值形参设为“const”,因为函数只能修改变量的副本。

使用“const”的原因是如果你通过引用传递更大的东西(例如有很多成员的结构体),在这种情况下,它确保函数不能修改它;或者更确切地说,如果您试图以常规方式修改它,编译器将报错。它可以防止它被意外修改。

使用const时要记住的一点是,从一开始就将对象设为const要比稍后再尝试将它们放入要容易得多。

当你想要某些东西保持不变时,使用const -它是一个附加的提示,描述了你的函数做什么以及期望什么。我见过许多C API可以处理其中的一些,特别是那些接受C -string的API !

我更倾向于省略cpp文件中的const关键字,而不是头,但由于我倾向于剪切+粘贴它们,它们将同时保留在两个地方。我不知道为什么编译器允许这样做,我猜这是编译器的事情。最佳实践肯定是将const关键字放在两个文件中。

做一个VB。NET程序员需要使用具有50多个公开函数的c++程序,以及偶尔使用const限定符的.h文件,很难知道何时使用ByRef或ByVal访问变量。

当然,程序通过在出错的行上生成一个异常错误来告诉您,但是随后您需要猜测2-10个参数中哪一个是错误的。

所以现在我有一个令人讨厌的任务,试图说服开发人员,他们应该真正定义他们的变量(在.h文件中),以一种允许自动创建所有VB的方法。NET函数定义容易。然后他们会自鸣得意地说:“读……文档”。

我写了一个awk脚本,它解析一个.h文件,并创建所有的Declare Function命令,但没有指示哪个变量是R/O vs R/W,它只完成了一半的工作。

编辑:

在另一位用户的鼓励下,我添加了以下内容;

下面是一个(IMO)格式不佳的.h条目的例子;

typedef int (EE_STDCALL *Do_SomethingPtr)( int smfID, const char* cursor_name, const char* sql );

从我的脚本的结果VB;

    Declare Function Do_Something Lib "SomeOther.DLL" (ByRef smfID As Integer, ByVal cursor_name As String, ByVal sql As String) As Integer

注意,第一个参数中缺少“const”。如果没有它,程序(或其他开发人员)就不知道第一个参数应该传递“ByVal”。通过添加“const”,它使.h文件自文档化,以便使用其他语言的开发人员可以轻松地编写工作代码。

由于形参是按值传递的,从调用函数的角度来看,是否指定const没有任何区别。将按值传递的参数声明为const基本上没有任何意义。

将值参数标记为“const”绝对是一件主观的事情。

然而,我实际上更喜欢将值形参标记为const,就像您的示例中一样。

void func(const int n, const long l) { /* ... */ }

对我来说,这个值清楚地表明函数的参数值永远不会被函数改变。它们在开始和结束时的值是一样的。对我来说,这是保持函数式编程风格的一部分。

对于一个简短的函数,在那里使用'const'可以说是浪费时间/空间,因为通常很明显函数不会修改实参。

然而,对于较大的函数,它是一种实现文档的形式,由编译器强制执行。

我可以肯定,如果我用'n'和'l'进行一些计算,我可以重构/移动计算,而不用担心得到不同的结果,因为我错过了一个地方,其中一个或两个都改变了。

因为它是一个实现细节,所以不需要在头文件中声明值形参const,就像不需要声明与实现使用的同名的函数形参一样。