const 的作用

目录

1. const的作用

2. const修饰

  2.1 修饰变量

  2.2 修饰指针

  2.3 修饰成员变量

  2.4 修饰成员函数

  2.5 修饰函数参数

  2.6 修饰返回值

3. const函数可以调用非const函数吗?

4. const一定要一经定义就初始化吗?

5. const修饰的函数和成员变量都存在哪里?


1. const的作用

        C++中,const 关键字用于定义一个常量值,即定义后不能被改变的值。const 可以用在多种上下文中,用于增强程序的可读性和安全性,因为它能明确地告诉编译器和其他阅读代码的人某个值是不应该被修改的。

2. const修饰

  2.1 修饰变量
1. 常量变量
    const int maxUsers = 100; 
    在这里,maxUsers 被定义为一个整型常量,它的值被设置为100,并且无法被更改。
2. 常量引用
    const int& ref = someOtherVariable;
    这里,ref 是 someOtherVariable 的一个常量引用,
    这意味着不能通过 ref 来修改 someOtherVariable 的值。
  2.2 修饰指针
1. 常量指针:指向常量的指针
    const int* ptr;
    上面的代码定义了一个指针ptr,指向一个int类型的常量,
    不能通过ptr来改变这个整数的值,但是ptr可以指向另一个整数。

2. 指针常量:指针本身是一个常量
    int value = 0;
    int otherValue = 1;
    int* const ptr = &value;

    这里,ptr是一个常量指针,它必须在定义时被初始化,
    并且之后不能再指向其他的地址,但是ptr指向的value的值是可以被修改的。
  2.3 修饰成员变量

        在下面例子中,staticValue 是一个静态常量成员,它属于类本身而不是类的实例,并且它的值在定义时就必须被初始化。instanceValue 是一个实例常量成员,它在每个类实例中都是唯一的,并且必须在构造函数的初始化列表中被初始化

class MyClass {
public:
    static const int staticValue = 10; // 静态常量成员
    const int instanceValue; // 实例常量成员
    MyClass(int val) : instanceValue(val) {} // 初始化常量成员的构造函数
};
  2.4 修饰成员函数

      在类成员函数后面使用 const 关键字表示该成员函数不会修改类的任何成员变量。

class MyClass {
public:
    int getValue() const {
        return value;
    }
private:
    int value;
};

         在这个例子中,getValue 函数被声明为 const,这意味着它保证不会修改对象的任何成员变量,甚至不能调用对象的其他非const成员函数。

  2.5 修饰函数参数

        const用来修饰函数参数时,它表示函数不会修改传入的参数。如果参数是指针或引用,这就变得特别有用,因为它保证了函数不会改变指针或引用所指向的数据。

void foo(const int* ptr); // 函数不会通过ptr修改所指向的整数

`const`关键字修饰函数参数有以下几个作用:

1. 提高函数安全性:
   当参数被`const`修饰时,它告诉用户和编译器这个参数在函数内部不会被修改,保护了数据不会被无意或恶意更改。

2. 生成更多的编译错误:
   如果函数内部的代码尝试修改了`const`修饰的参数,编译器会生成错误。这有助于发现潜在的bug。

3. 使函数对`const`和非`const`数据都适用:
   当你有一个`const`对象时,只有`const`成员函数可以被调用。同样,只有接受`const`参数的函数可以接收`const`对象作为实参。这增加了函数的适用性。


void bar(const int& ref); // 函数不会修改通过ref引用的整数

         const & 作为函数参数作为函数参数时具有很大的作用,作用如下:

  1. 避免拷贝:
    当你传递一个大的对象给函数时,如果不使用引用,则会创建该对象的一个副本,这涉及到调用拷贝构造函数和可能的临时对象的创建,这可能是非常耗费性能的。如果你使用引用传递,那么复制的开销就会被省略,因为引用只是原始对象的一个别名。

  2. 保证不修改实参:
    当你将引用传递给函数时,函数可能会修改引用所指向的数据。如果你不希望函数修改传入的参数,你可以将参数声明为const。这样,函数就不能通过引用修改参数的值,这对于确保数据的完整性非常重要。

  3. 支持多态行为:
    当函数接受const &参数时,它可以接受传值、非const引用、const引用,以及临时对象。这意味着函数的使用变得更加灵活。

         使用const &作为参数,尤其是对于大型对象来说,既可以提高效率又可以保证函数不会意外地修改数据,同时还能保持代码对不同类型参数的接受度。

  2.6 修饰返回值

        const也可以修饰函数的返回值,这通常用在返回引用的情况下,以防止返回的引用被用来修改其指向的值。在返回值的场景中,对基本数据类型使用const修饰通常没有太大意义,因为它们是通过值返回的,不允许修改返回的值本来就是默认行为。

const int& getMax(const int& a, const int& b) {
    return (a > b) ? a : b;
}

// 使用getMax的地方不能通过这个函数来修改a或b的值

3. const函数可以调用非const函数吗?

        在C++中,`const`成员函数承诺不会修改对象的状态。这意味着在`const`成员函数内部,你不能直接修改对象的任何非`mutable`成员变量,也不能调用任何可能会修改对象状态的非`const`成员函数,因为这些操作都有潜在的修改对象状态的风险。

        然而,`const`成员函数可以调用其他`const`成员函数(因为这些函数也承诺不会改变对象的状态),可以读取对象的成员变量,也可以调用外部的非成员函数或其他对象的成员函数,只要这些操作不会修改当前对象的状态。

        在`const`成员函数中想要调用非`const`成员函数或修改成员变量的唯一方法是通过使用`const_cast`来移除对象的`const`限定符(但这是危险的,因为它违反了`const`成员函数的承诺,可能导致未定义行为,特别是如果对象本身是`const`的话)或者通过使用`mutable`关键字来声明成员变量(`mutable`成员变量可以在`const`成员函数中被修改)。

class MyClass {
public:
    int nonConstFunc() { return ++nonConstVar; } // 非const成员函数,可以修改状态

    int constFunc() const {
        return constVar; // 可以访问成员变量,但不能修改它们
        // return nonConstFunc(); // 错误:在const成员函数中不能调用非const成员函数
    }

    void setMutable(int val) const {
        mutableVar = val; // 即便是const成员函数,也可以修改mutable成员变量
    }

private:
    int nonConstVar = 0;
    mutable int mutableVar = 0; // mutable允许在const函数中被修改
    const int constVar = 1;     // const成员变量,一经初始化不能更改
};

        在这个例子中,`constFunc()`是一个`const`成员函数,它不能调用`nonConstFunc()`,因为后者可能会修改对象的状态。但它可以修改`mutableVar`,因为这个变量被声明为`mutable`。如果尝试在`constFunc()`中修改`nonConstVar`或`constVar`,将会导致编译错误。

4. const一定要一经定义就初始化吗?

        在C++中,`const`变量一经定义必须立即初始化,因为之后你将无法修改它们的值。这是因为`const`关键字用于定义常量值,这意味着该值在编译时就应该是已知的,并且在程序的整个生命周期中不会改变。


const int myConst = 10; // 正确:const变量在定义时初始化
const int myConst; // 错误:未初始化的const变量
myConst = 10;     // 错误:不能给const变量赋值

        编译器会报错,因为`myConst`被定义为`const`但没有被初始化。一旦定义了`const`变量,就不能再给它赋值,因为`const`本意就是表明该变量的值在定义后不可变。

        此外,对于类的成员`const`变量,你必须在构造函数的初始化列表中对其进行初始化,因为成员变量在构造函数体执行前就应该被初始化,对于const成员变量,你不能在类体内为其赋值,也不能在构造函数体内赋值,因为这两种方式都相当于在声明之后修改变量的值,这是不允许的。如果一个类有多个构造函数,每个构造函数都需要在其初始化列表中初始化const成员变量,以确保这个成员变量在任何情况下都会被正确地初始化。

class MyClass {
public:
    const int myConst;

    MyClass(int val) : myConst(val) { // 正确:在初始化列表中初始化const成员
        // 构造函数体
    }
};

        在这个例子中,`myConst`是一个`const`成员变量,它在`MyClass`的构造函数的初始化列表中被初始化。如果你没有在初始化列表中初始化它,你将得到一个编译错误。

        然而,你可以延迟非局部`const`变量(如全局变量或`namespace`作用域内的`const`变量)的初始化,只要在初始化之前不使用它们:

// header.h
extern const int globalConst; // 声明一个全局const变量,但未初始化

// source.cpp
#include "header.h"
const int globalConst = 10; // 在某个源文件中初始化该变量

        这种方式允许在程序的一个单独部分中定义`const`变量的实际值。但是,这种情况下的`const`变量实际上被当作链接时的常量来处理,仍然需要在程序的某个点上被初始化。

5. const修饰的函数和成员变量都存在哪里?

        在C++中,`const`关键字可以用于修饰函数成员和成员变量,它们的作用和存储位置有所不同:

        1. `const`修饰成员变量:
           `const`成员变量表示该变量的值在对象生命周期内不可变。它们存储在对象所占用的内存中,与其他非`const`成员变量一样。`const`成员变量必须在构造函数的初始化列表中初始化,因为它们的值无法在之后被更改。

class MyClass {
   public:
       const int constMember; // const成员变量

       MyClass(int value) : constMember(value) // 必须在初始化列表中初始化
   };

2. `const`修饰成员函数:

        当`const`关键字用于成员函数时,它不影响成员函数的存储位置。成员函数是否带`const`修饰,其代码都存储在程序的代码段(或相似的内存区域)。不过,`const`修饰成员函数表示该函数不会修改对象的任何非`static`成员变量,也不会调用任何非`const`成员函数。

  class MyClass {
   public:
       void constFunction() const {
           // 这里不能修改任何成员变量
       }
   };

        这意味着`const`成员函数可以被用于`const`对象,同时确保了调用该函数不会更改对象的状态。

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值