"const" 在变量、函数参数和成员函数中的含义是什么?

39
阅读C++教程和代码时,我经常会遇到“const”关键字。
我看到它被用在以下方式:
const int x = 5;

我知道这意味着x是一个常量变量,可能存储在只读内存中。
但是,这些是什么?
void myfunc( const char x );

并且

int myfunc( ) const;

?


15
“常量变量”:这有点矛盾!;) - Flinsch
3
必要的C++ FAQ链接:http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.10该链接讨论了在C ++中如何正确使用const关键字,并解答了一些常见问题。建议阅读以加深对const正确性的理解。 - Charles Salvia
可能是在C语言中如何使用const关键字的重复问题。 - Björn Pollex
相关链接:https://dev59.com/32035IYBdhLWcg3wJccw - Jan Schultke
9个回答

58
void myfunc(const char x);

这意味着参数x是一个char类型的变量,其值在函数内部无法更改。例如:

void myfunc(const char x)
{
  char y = x;  // OK
  x = y;       // failure - x is `const`
}

对于最后一个:

int myfunc() const;

除非在类声明内部,否则这是非法的- const成员函数防止修改任何类成员-不能使用const非成员函数。在这种情况下,定义将是这样的:

int myclass::myfunc() const
{
  // do stuff that leaves members unchanged
}

如果您需要在 const 成员函数中修改特定的类成员,您可以将它们声明为 mutable。一个例子是成员 lock_guard,它使该类的 const 和非const 成员函数线程安全,但在其自身内部操作期间必须更改。


整个设计的目的并不是为了启用const方法的使用,而是为了能够在const对象上调用任何方法...因此,可变成员不是指在const方法中可以更改的成员,而是指在其他情况下允许更改的成员。 - user1115652
@ufotds - 正确 - 不要将变量设为mutable,仅因为您在成员函数上误解了const的含义而导致代码无法编译。 - Steve Townsend

10

第一个函数示例基本上没有意义。更有趣的一个示例是:

void myfunc( const char *x );

这告诉编译器*x内容不会被修改。也就是说,在myfunc()中你不能执行如下操作:

strcpy(x, "foo");

第二个例子是关于 C++ 成员函数的,意味着调用该函数时对象的内容不会被改变。

所以给定:

class {
  int x;
  void myfunc() const;
}

someobj.myfunc()不允许修改任何东西,比如:

x = 3;

第一个例子实际上可以帮助编译器生成更优化的代码,尽管大多数现代编译器很可能会自己找出变量是否被修改。 - Tommy Andersen
2
第一个示例还可以防止意外修改。虽然从调用者的角度来看这并不重要,但有时声明每个参数和局部变量为“const”非常有帮助,因为修改它们可能会指向错误或糟糕的设计。 - Philipp
即使它毫无意义(这一点我完全同意@Philipp),你至少应该解释一下为什么。(但是现在已经被告知是错误的,所以不必再解释了。) - sbi

3
这是:

void myfunc( const char x );

意味着你不能在函数中更改 x,也就是说这是非法的:
void myfunc( const char x ) {
    x = ...;
}

当:

int myfunc() const;

只有当myfunc()是类中的一个方法时才有意义;这基本上意味着该方法不能修改类实例(即在调用instance.myfunc()之前和之后,实例的状态将保持不变)。


3

const 在变量标识符前面,表示该变量可以被初始化,并且之后不能再修改。

const 在类方法名称之后,表示该方法将不会修改类的可观察状态。而 mutable 关键字允许修改内部数据。

const 在指针或引用变量前,表示该标识符不会用于修改引用的数据,尽管可以通过其他方式进行更改。

const int *pInt = &x;

常量也可以用来表示指针本身不能被修改:

int * const pInt = &x;

1
我在http://duramecho.com/ComputerInformation/WhyHowCppConst.html找到了一个非常好的解释。
基本上,所有的混淆都在于关键字const的不同用法。根据你放置const的位置,你告诉编译器某些东西应该是不可变的,或者某些东西不能改变其他东西。'something'可能是一个变量、一个指针或一个函数/方法,你不希望它能够改变传递给函数或对象成员变量的值。

2
这只是谷歌的热门搜索结果。 - Yash

0

const 限定符表示一个被定义为 const 的变量/指针不能被程序更改,并且它将通过显式初始化或硬件相关手段接收其值。

在参数声明中定义为 const 的指针,函数代码将不会修改其所指向的内容。基本上,您可以使用该指针,并且它几乎起到 "只读" 的作用。

例如:

void foo(const char *x)
{
    while(*x)
    {
        if(*x==' ') cout << '-'; //printing - when a space is encountered
        else cout << *x;
        x++;
    }
}

上述函数很好,不会显示任何错误。但是如果foo有任何可以更改传递的字符串的东西。比如一个将空格替换为$的函数。不是打印$而是将其更改为$。类似于这样:

void foo(const char *x)
{
    while(*x)
    {
        if(*x==' ') *x = '$'; //printing - when a space is encountered
        else cout << *x;
        x++;
    }
}

那么它就无法编译,即将一个值赋给只读内存位置的错误。


0
被接受的答案(以及我浏览过的其他答案)都是不正确的。 不要假设“const”意味着标识符(比如你的x)“在函数内部无法更改”。它意味着标识符不能直接更改。但它很容易被更改。
考虑完整的程序(为新手编写):
#include <iostream>

void break_const(const int x) {
    const int* x_ptr = &x;
    std::intptr_t z = reinterpret_cast<std::intptr_t>(x_ptr);
    int* hacked = reinterpret_cast<int*>(z);
    *hacked = 3;
    std::cout << "x = " << x << std::endl;
}

int main() {
    break_const(5);
    return 0;
}

输出结果为 "x = 3."

编辑:我还应该补充一点,我的说法 "这意味着标识符不能直接更改" 有些不准确。对于整数来说,这是可以的。但对于更复杂的类型,const 的含义就更少了(例如类中的 mutable)。


但是你为什么要这样做呢?如果你想要更改它,就不要声明为const。 - Michael Kotzjan
@M. Kotzjan,我同意你的观点,不应该这样做。问题在于你确实可以这样做。因此,接受的答案中类似“这意味着参数x是一个char类型,在函数内其值无法更改”的说法是错误的。 - Otto

0

两者之间的区别在于第一个具有类型void(char),而第二个具有类型int()const

具有带有const结尾的此类类型的函数只能是类的成员函数,并且这意味着从类外部看,成员函数不会改变类值(指this所指向的值)。编译器会对此进行一定程度的检查,任何直接对常量成员函数中类成员的写入都将导致编译时错误,并且该函数只能直接调用其自身的常量成员函数(存在特殊指令,可以告诉编译器成员写入不会从外部更改类的值。这通过使用mutable关键字实现)。

在您提供的函数中,其中一个参数的类型为char const。这种参数在其函数内部无法更改。它对函数类型或调用者没有影响。


虽然这些类型肯定是正确的,但对于新手来说,它们很可能是胡言乱语。 - sbi

0

void myfunc(const char x) 非常类似于你的例子中的 const int x = 5:它声明了一个在函数 myfunc 内部可用的常量。由于它是一个常量,它的值不能被改变。

int myfunc() const 是一个类的成员函数。其中的 const 表示该函数不会改变执行函数的类实例。因此,在函数内部,你不能像这样做:this->foo = 7 或者调用其他非 const 的函数。


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