C++中的const指针和const引用有何区别?

16
根据下面的程序,我可以理解到,在引用前加上 const 关键字意味着引用了一个 常量引用(const reference) 指向一个常量值,这个理解正确吗?
#include <iostream>
using namespace std;

struct s
{
    int x;
};

int main(void)
{
    s a = {10}, b = {30};

    // IN POINTERS ----------------
    const s* ptrToConstValue;
    ptrToConstValue= &a;
    //ptrToConstValue->x = 30; 
    ptrToConstValue = &b;

    s* const constPtrToNonConstVaue = &a;
    constPtrToNonConstVaue->x = 40;
    //constPtrToNonConstVaue = &b;

    const s* const constPtrToConstValue = &a;
    //constPtrToConstValue = &b;
    //constPtrToConstValue->x = 30;


    // IN REFERENCES -------------
    const s& seemsToBeConstRefToConstValue = a;
    //s = b;
    //s.x = 30;

    return 0;
}

如果您使用 (const T)&,它将始终被解析为“(const T)&”,而不是“const (T&)”。 - Kerrek SB
6个回答

19

所以混淆的地方在于:

X x;

X* px       = &x; // pointer to x
X* const px  = &x; // *const pointer* to x

const X* px   = &x; // pointer to *const x*
X const* px   = &x; // identical

const X* const px = &x; // *const pointer* to *const x*

现在在引用中,指针部分总是const的:

X& rx = x;       // ref to x

X const& rx = x; // ref to const x
const X& rx = x; // identical

15

引用类型总是const,因此您不需要为它们使用const关键字;事实上,这是被禁止的。

所以您拥有:

S*                ps;   //  Non-const pointer to a non-const value
S const*          psc;  //  Non-const pointer to a const value
S* const          pcs;  //  Const pointer to a non-const value
S const* const    pcsc; //  Const pointer to a const value

,但只有:

S&                rs;   //  (const) reference to a non-const value
S const&          rsc;  //  (const) reference to a const value

将紧跟类型名称后面的const移动到声明开头可能会让读者感到困惑,但这样做是可以的。


奇怪的是,将const移到类型后面整个过程让我感到困惑。我猜这是因为它似乎是一种比我学习时更近期出现的编码风格。我习惯于看到const R&,我认为这种风格更常见。然而,我可以理解为什么你上面的风格更易于理解,因为它遵循从右到左的阅读方式。 - Firedragon
@Firedragon 其背后的动机有两个。首先,当然,在大多数情况下,你没有选择:const必须遵循常量。其次是关于typedef的问题:如果你有像typedef char* pc;这样的东西,并写上const pc,那么什么是常量。我也是在合法时首次看到const在左边;它是typedef参数使我信服的。 - James Kanze

6

一旦引用被初始化后,就无法更改。因此,谈论“const引用”是没有意义的。引用本质上代表了值,在这种情况下,该值是不可变的,也无法更改。


“初始化后无法更改引用”是什么意思?这段代码可以编译通过:void bar(Box& a) { a.data = 33; a = Box(100); } - frankelot

6
是的,引用前面的const表示通过它引用的对象被视为常量(即您无法访问非常量方法或数据成员)。
引用本身在任何情况下都是“const”的,因为一旦初始化就不能修改其引用不同的对象。

也许在这里使用“值”比“对象”更合适? - Karl Knechtel

4

引用既不是const也不是非const,它只是一个引用。您无法更改引用的引用对象(这就是它存在的原因),因此谈论const性质是没有意义的。在您的示例中,该引用之所以被称为const引用,是因为它引用了一个const类型。


4
在引用前面加上const关键字意味着对常量的const引用,正确吗?
这意味着您无法使用引用来更改对象。
引用所指的对象仍然可以被修改,但不能使用引用进行修改:
- 如果它引用的对象确实是可修改的,则可以使用const_cast去除const性质,然后修改对象。 - 但如果对象是不可修改的,则尝试通过去除const性质来修改它会导致未定义的行为。

3
+1 是针对“使用引用”的,其他答案似乎让人觉得只要使用一个 const 引用,对象本身就会突然变成常量。请注意,这种理解是不正确的。 - leftaroundabout

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