C++函数语法/原型 - 括号后面的数据类型

7

我非常熟悉C/C++标准函数的声明。最近我看到了类似这样的内容:

int myfunction(char parameter) const

上面只是一个假设性的例子,我甚至不知道它是否有意义。我指的是参数之后的部分。常量。这是什么?

更真实的例子:

wxGridCellCoordsArray GetSelectedCells() const

这可以在这里找到。 那么该行末尾的const文本究竟是做什么的?

https://dev59.com/nWQo5IYBdhLWcg3whPgi - chris
请参考此链接:https://dev59.com/jnA75IYBdhLWcg3wuLnD - aaronman
@chris 很好。但是现在我有点困惑了。GetSelectedCells函数没有可以更改的参数吗? - itsols
@itsols,这是一个成员函数。因此,它有一个参数。 - chris
更新了答案以解释一些重要的差异。首先,将const添加到函数末尾会更改其签名,因此是函数的有效重载。其次,我解释了为什么使用mutable以及位掩码const和概念上的const之间的区别,并附上了一篇写得很好的文章来解释这种区别。希望这可以帮助到您。 - Paul Renton
4个回答

8

const关键字表示函数不会改变任何数据成员,除非它们被标记为mutable。
只有成员函数可以被标记为const,这意味着在函数内部不会更改任何成员。


唯一的例外是 const_cast。但是,如果有人重视自己的工作,我怀疑他们会使用它 =D - Paul Renton

5

在函数后面出现的const关键字可以保证函数调用者不会更改任何成员数据变量。它还会改变函数签名,这是一些C++程序员不太了解的事情。实际上,您可以通过在具有相同名称的函数后添加const关键字来重载C++中的函数。例如:

void changeValue() const;
void changeValue();

以上两个函数都是有效的,且彼此重载。我经常看到一些C++ API和框架使用这种重载来避免用户在const和非const函数中调用这些函数时出现大量编译错误。这是否是良好的C++软件工程尚有争议。我想这是不好的实践,但了解它会改变函数签名是很好的。

例如,给定以下类:

// In header
class Node {

public:

Node();

void changeValue() const;

~Node();

private:

int value;

};

// in .cpp

void Node::changeValue() const {
    this->value = 3; // This will error out because it is modifying member variables
}

这个规则有一个例外。如果您声明成员数据变量为mutable,则可以更改它,而无论函数是否声明为const。使用mutable是为罕见情况下的对象而声明常量,但实际上需要更改成员数据变量的选项。其潜在用途之一是缓存您可能不希望重复计算的值。这通常很少见...但了解它是很好的。关于Mutable的软件工程决策的良好参考是比特位const与概念const的概念。对于比特位const,程序员通知读者,当存在const时,该const对象的任何位都不应更改,除非进行const_cast。对于概念性const,想法是类的用户不应关心可变变量的位是否更改,因为这不会影响用户对类的使用的感知。这是一篇好的文章,解释了Mutable的区别以及使用Mutable的优点和缺点 - https://www.cprogramming.com/tutorial/const_correctness.html 例如,给出这个类:
// In header
class Node {

public:

Node();

void changeValue() const;

~Node();

private:

mutable int value;

};

// in .cpp

void Node::changeValue() const {
    this->value = 3; // This will not error out because value is mutable
}

副作用包括输出,所以这并不完全正确。 - chris
既然你的答案被接受了,你应该提到可以更改标记为mutable的数据成员,那么我会给你一个+1。 - aaronman
我来自过去 :) 我和 C 的日子可以追溯到 1990 年。但是我不记得在任何地方使用过这个 mutable 关键字。它对我没有用处。为什么我需要声明某些东西是常量,然后在函数内部说某些东西是可变的呢?我不太明白这些新事物的原因... 不管怎样,还是谢谢。 - itsols
@itsols 我强迫他不情愿地把它放进去了,我半同意你对mutable关键字无用性的看法,C++喜欢让你做任何你想做的事情。你知道const_cast吗? - aaronman
2
@itsols: 使用mutable的一个例子是当您的对象具有“上次访问时间”时间戳变量时。即使有人使用const方法访问对象,您也希望能够更新该变量。 - jxh
我添加了一个链接,解释了按位const与概念性const。这是大多数C++软件工程师在决定类架构时考虑的内容。 - Paul Renton

4
这是一种“防御性编程”技术,可帮助防范自己的编程错误。使用 const 修饰函数参数,表示该函数不应修改该参数,添加 const 会导致编译器防止您无意中这样做。同样,如果您编写不应更改类的任何成员变量的成员函数,则可以像那样将整个函数声明为 const,从而防止您这样做。
它还有助于使您的代码自我记录。向参数添加 const 告诉用户:“此函数不修改此参数”。向成员函数添加 const 告诉用户:“此函数不修改类的任何成员”(除了显式的可变成员)。
除非确实需要访问某些内容,否则限制访问应通常被视为一件好事。这正是为什么你不会经常以root身份登录自己的系统,即使你可以这样做,如果你这样做,你会拥有更多的权限。

我喜欢“防御性”编程和自我记录。对于这些技巧点赞。 - itsols

2
const 关键字在方法后面表示隐式的 this 参数(它被设置为调用该方法的对象的地址)指向一个常量对象。
在 C++ 中,成员函数可能如下所示:
class Foo {
    int x;
    mutable int y;
public:
    void bar ()       {
        Foo *me = this;          // * this is an implicit parameter
                                 //   that points to the instance used
                                 //   to call bar()
        assert(&x == &this->x);  // * accesses to class members are
                                 //   implicitly taken from this
        x = 1;                   // * can modify data members
    }
    void bar () const {
        // Foo *me = this;       // * error, since "bar() const" means
                                 //   this is a "const Foo *"
        const Foo *me = this;    // * ok
        // x = 1;                // * error, cannot modify non-mutable
                                 //   members of a "const Foo"
        y = 0;                   // * ok, since y is mutable
    }
};

在C语言中,类似的功能是通过访问指向struct Foo *const struct Foo *的函数实现的:

struct Foo {
    int x;
    int y;
};

void Foo_bar (Foo *this)        { /* ... */ } /* can modify this->x and this->y */
void cFoo_bar (const Foo *this) { /* ... */ } /* cannot modify this->x nor this->y */

在C语言中没有可变的类似于mutable的 analong。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接