乐趣区

关于c++:C中const和constexpr的作用

目录

背景

const 关键字

constexpr 关键字

总结

背景

很多 C++ 的初学者看到 const 这个关键字的第一反馈都是一头雾水,次要是因为 const 能够呈现在很多的地位,以及前面退出的 constexpr 更是经常感到困惑,明天就为大家一一解释呈现它们的含意和以及作用

const 关键字

1. const 润饰变量

这是最根本的一种用法,顾名思义,就是将该变量润饰为常量,从而不能够批改。很多的全局变量都是通过常量来进行润饰,须要留神的是,应用 const 关键字润饰的变量须要立即初始化

// 润饰局部变量,全局变量,成员变量
const int a = 2;
a = 3;    // 谬误,表达式必须是可批改的左值,意思就是 a 是个常量,无奈批改

// 还有人习惯这种写法,作用是一样的,看集体爱好即可
int const b = 22;

// 润饰函数参数
void test(const int num) {num = 3;    // 谬误,表达式必须是可批改的左值,意思就是参数 num 是个常量,无奈批改}
2. 润饰指针

尽管指针也是一种变量,不过当 const 与指针呈现在一起的时候,地位的不同会产生不同的作用,所以独自拎进去讲

// 第一种状况:指针常量
int a = 2;
const int *p = &a;    // const 作用:使其无奈通过指针来批改变量
*p = 3;    // 谬误,表达式必须是可批改的左值
a = 4; // 正确
cout << *p << endl;    // 4
// 同样地,有人习惯这种写法,作用是一样的,看集体爱好即可
int const *p2 = &a;

// 第二种状况:常量指针
int a = 2;
int* const p = &a;    // const 作用:使指针 p 无奈指向其余变量
int b = 3;
p = &b;    // 谬误,表达式必须是可批改的左值
3. 润饰函数

const用于润饰函数也是最困惑的中央,次要起因在于它能够呈现在不同的中央,并且每一个都有不同的含意。接下来为一一为大家解释

// 润饰函数返回值,这种用法毫无意义,它的作用相当于将返回值润饰为了常量,然而返回值是一个将亡值,在返回之后要么赋值给了其余的变量,而后其余变量能够持续批改,要么就随着来到作用域而被开释内存。所以通常不会这么应用。const int getNum() {return 3;}

// 润饰成员函数,通常加在成员函数的开端,作用申明该成员函数为只读函数,即无奈批改任何成员变量的值
class Student {
   public:
    void test() const {
        member = 3;    // 谬误,表达式必须是可批改的左值,因为 member 是成员变量,而 test 函数被 const 润饰过后无奈批改成员变量
        int b = 3;
        b = 4;    // 正确
    }

   private:
    int member = 2;
};
4. const 援用

这是 const 最罕用的一种形式,通常用于函数的参数列表中,因为咱们晓得在 C++ 中函数参数有 3 中传递形式,别离是 值传递 指针传递 (或者叫地址传递), 援用传递,前两种在传递时都会发成拷贝行为

指针自身也是一个变量,在 32 位操作系统下占用 4 个字节,64 位零碎占用 8 个字节,尽管的拷贝老本会低一点,然而在大量的调用过程中也比拟可观

所以通常咱们采纳传递援用的形式,因为援用只是变量的一个别名,不占用内存,所以不会产生拷贝行为。然而援用传递有一个问题,那就是形参能够扭转实参的值。所以为了防止意外批改导致实参的值产生改,通常会采纳 const 加上援用的形式传递参数

void test(const Student &s) {...}

constexpr 关键字

constexprC++11 中引入的一个关键字,它的作用次要是用来润饰一些函数和变量,使其成为常量表达式,从而在编译器就能够进行计算,进一步提高程序运行期的效率

常量表达式:指的是有一个或多个常量组成的表达式,在理论开发中常常会接触到常量表达式,比方数组长度就必须是一个常量表达式

int arr[5];    //    正确,长度 5 是由 1 个常量组成的常量表达式
int arr2[3 + 4];    // 正确,长度 3 + 4 是由 2 个常量组成的常量表达式
int n = 10;
int arr3[n];    // 谬误,长度 n 是由变量形成,不是常量表达式
1. 润饰变量

由此能够看出,只有是常量表达式,咱们就能够通过 constexpr 来进行润饰,从而进步程序的效率,比方上面这样

contexpr int n = 2 + 2;    // 正确,2+ 2 是常量表达式,n 将会在编译器进行计算
int arr[n] = {11, 22, 33, 44};    // 正确,n 是一个常量表达式
cout << arr[2] << endl;    // 33
2. 润饰一般函数

constexpr还能够用于润饰函数的返回值,在 C++11 中被 constexpr 润饰的函数只能是非 void 类型的函数,而且必须十分简短,通常只有一句 return 表达式。不过在后续的 C++14/17/20 规范中进一步的放宽了这了限度,都能够通过编译了

constexpr int test() {return 1 + 1;}
3. 润饰构造函数

constexpr还能够用于润饰自定义类型,不过有一个前提条件,就是该自定义类型具备 constexpr 润饰的构造函数,并且该构造函数不能有具体实现,否则会编译报错

class Student {
   public:
    constexpr Student(const char* name, int age) : name_(name), age_(age) {}

    void print() const { cout << name_ << '' << age_ <<'\n';}

   private:
    const char* name_;
    int age_;
};

void test() {constexpr Student s{"zhangsan", 18};
    s.print();}

总结

const能够润饰编译期和运行期的常量,而 constexpr 只能润饰编译期的常量

const在依然能够通过 const_cast 类型转换来批改值,而 constexpr 是不能够批改的,其实能够将 const 了解为只读变量更合乎其含意

const只能用于非动态成员函数,而 constexpr 能够和成员,非成员,构造函数一起应用

再有常量示意的场景,尽可能的加上 constexpr 来让编译期进行计算

然而大面积的 constexpr 也会面临相应的减少编译工夫的危险

退出移动版