C++中const和constexpr关键字解析:常量、函数
很多
C++
的初学者看到const
这个关键字的第一反应都是一头雾水,主要是因为const
可以出现在很多的位置,以及后面加入的constexpr
更是常常感到困惑,今天就为大家一一解释出现它们的含义和以及作用
const关键字
修饰变量
这是最基本的一种用法,顾名思义,就是将该变量修饰为常量,从而不可以修改。很多的全局变量都是通过常量来进行修饰,需要注意的是,使用const
关键字修饰的变量需要立刻初始化
// 修饰局部变量,全局变量,成员变量 const int a = 2; a = 3; // 错误,表达式必须是可修改的左值,意思就是a是个常量,无法修改 // 还有人习惯这种写法,作用是一样的,看个人喜好即可 int const b = 22; // 修饰函数参数 void test(const int num) { num = 3; // 错误,表达式必须是可修改的左值,意思就是参数num是个常量,无法修改 }
修饰指针
虽然指针也是一种变量,不过当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; // 错误,表达式必须是可修改的左值
修饰函数
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; };
const引用
这是const
最常用的一种方式,通常用于函数的参数列表中,因为我们知道在C++
中函数参数有3中传递方式,分别是值传递,指针传递(或者叫地址传递),引用传递,前两种在传递时都会发成拷贝行为
指针本身也是一个变量,在32位操作系统下占用4个字节,64位系统占用8个字节,虽然的拷贝成本会低一点,但是在大量的调用过程中也比较可观
所以通常我们采用传递引用的方式,因为引用只是变量的一个别名,不占用内存,所以不会发生拷贝行为。但是引用传递有一个问题,那就是形参可以改变实参的值。所以为了避免意外修改导致实参的值发生改,通常会采用const
加上引用的方式传递参数
void test(const Student &s) { ... }
constexpr关键字
constexpr
是C++11
中引入的一个关键字,它的作用主要是用来修饰一些函数和变量,使其成为常量表达式,从而在编译器就可以进行计算,进一步提高程序运行期的效率
常量表达式:指的是有一个或多个常量组成的表达式,在实际开发中经常会接触到常量表达式,比如数组长度就必须是一个常量表达式
// 正确,长度5是由1个常量组成的常量表达式 int arr[5]; // 正确,长度3+4是由2个常量组成的常量表达式 int arr2[3 + 4]; int n = 10; // 错误,长度n是由变量构成,不是常量表达式 int arr3[n];
修饰变量
由此可以看出,只要是常量表达式,我们就可以通过constexpr
来进行修饰,从而提高程序的效率,比如下面这样
// 正确,2+2是常量表达式,n将会在编译器进行计算 contexpr int n = 2 + 2; // 正确,n是一个常量表达式 int arr[n] = {11, 22, 33, 44}; // 33 cout << arr[2] << endl;
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
也会面临相应的增加编译时间的风险
欢迎来到C++专栏!本专栏将免费为大家全面介绍C++编程语言的基础知识、面试问题、高级特性和实际应用技巧。 无论您是学生还是有一定经验的开发者,本专栏都将为您提供有价值的内容。我们将通过丰富的例子来帮助您更好地理解和掌握C++编程语言,让您的开发之路更加顺畅和高效。 感谢您的关注和支持,期待与您一起探索C++的奥秘!