C++ const关键字
记得有次面试carmera turning岗,面试官让我谈谈const关键字的作用我提到被const修饰变量会存入.rodata的只读数据段不可更改,面试官好像不是很满意,现在想想carmera turning岗位好像主要用C++,面试官当时是想让我说说C++中const关键字的作用。C++中const关键字的作用比起C语言就多了不少。
1. 用于声明常量
常量一旦被初始化,就不能被修改。在C++中被const修饰的变量仅在当前文件中可见
const int MAX_SIZE = 100; // 声明一个常量
MAX_SIZE = 200; // 错误:常量不能被修改
2. 指向常量的指针
指向常量的指针表示指针所指向的值是常量,不能通过指针修改该值。
const int* ptr; // 指向常量的指针
int value = 5;
ptr = &value;
// *ptr = 10; // 错误:不能通过指针修改常量值
3. 常量指针
常量指针表示指针本身是常量,不能改变指针指向的地址。
int value = 5;
int* const ptr = &value; // 常量指针
*ptr = 10; // 合法:可以通过常量指针修改指针指向的值
// ptr = nullptr; // 错误:不能改变常量指针的指向
4. 常量成员函数
成员函数的末尾增加一个const会变为常量成为函数,这个成员函数不会修改该对象里面的任何成员变量的值等。
void noone() const
{
Hour += 10; //错误,常量成员函数不可以修改成员变量值
}
注意:
普通函数(非成员函数)末尾是不能加const的。
成员函数的声明和实现代码分开的情形下,不但要在成员函数的声明中增加const,也要在成员函数的实现中增加const。
5.常量对象
const MyClass obj;
obj.display();
被const修饰的对象,只能调用常量成员函数,且不能修改成员变量。
mutable
被mutable修饰的成员变量永远处于可变状态,即使是在常量成员函数中。引入mutable关键字的意义在于,满足在某些情况下需要常量对象,调用常量成员函数修改一些特定值的情况。
class Time {
private:
mutable int myHour; // 允许在const成员函数中修改
int myMinute;
int mySecond;
public:
void noon() const {
myHour = 12;
}
};
6.修饰函数参数
输入参数采用“指针传递”加 const 修饰可以防止意外地改动该指针,起到保护作用。
void StringCopy(char *strDestination, const char *strSource);
常量左值引用
void Func(const A &a)。
相较于void Func(A a)的写法上面的写法传入引用省去了临时对象的构造、复制、析构过程,加入const变为常左值引用防止参数被意外修改,而且既可以接受左值引用,又可以接受右值引用,增加程序的通用性。
7.修饰函数返回值
const 修饰内置类型的返回值,修饰与不修饰返回值作用一样。
#include<iostream>
using namespace std;
const int Cmf()
{
return 1;
}
int Cpf()
{
return 0;
}
int main(void)
{
int _m = Cmf();
int _n = Cpf();
cout<<_m<<" "<<_n;
system("pause");
return 0;
}
const 修饰自定义类型的作为返回值,此时返回的值不能作为左值使用,既不能被赋值,也不能被修改。
#include <iostream>
class MyClass {
public:
MyClass(int value) : value_(value) {}
int getValue() const { return value_; }
void setValue(int value) { value_ = value; }
private:
int value_;
};
// 返回一个const MyClass对象的引用
const MyClass getConstObject() {
static MyClass obj(10);
return obj;
}
int main() {
//不可被赋值
MyClass newObj(20);
getConstObject() = newObj;
//不可被修改
getConstObject().setValue(20);
//不可作为左值
MyClass& objRef = getConstObject();
return 0;
}
const 修饰指针作为返回值,函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加 const 修饰的同类型指针。
const int* getConstPointer() {
static int* a;
return a;
}
int main() {
const int* p = getConstPointer();//不能去掉const
return 0;
}
constexpr
constexpr 变量在编译时必须能够求值。这意味着编译器在编译时就可以确定该变量的值。
constexpr int max_size = 100; // 编译时常量
constexpr 函数
constexpr 函数是一种在编译时可以计算其返回值的函数。为了成为 constexpr 函数,该函数必须满足一些条件,例如函数体必须包含一个返回语句,并且所有参与计算的参数和操作都必须是编译时可知的。
constexpr int factorial(int n) {
return (n <= 1) ? 1 : (n * factorial(n - 1));
}
在上面的例子中,factorial 函数在编译时即可计算其结果:
constexpr int result = factorial(5); // result 在编译时计算出 120
constexpr 构造函数
在 C++11 及其后的标准中,构造函数也可以被标记为 constexpr,这允许在编译时创建常量表达式对象。
class Point {
public:
constexpr Point(double x = 0, double y = 0) : x_(x), y_(y) {}
constexpr double getX() const { return x_; }
constexpr double getY() const { return y_; }
private:
double x_;
double y_;
};
constexpr Point p(3.0, 4.0);
constexpr double x = p.getX(); // x 在编译时计算出 3.0
constexpr double y = p.getY(); // y 在编译时计算出 4.0
constexpr 和 const 的区别
const 仅表示对象不可修改,但不要求编译时求值。
constexpr 要求表达式在编译时求值,因此可以用于定义编译时常量。
constexpr 的限制
为了使函数成为 constexpr,需要满足以下条件:
函数必须有一个返回值。
函数体必须是一个编译时常量表达式。
参数和返回值都必须是字面值类型(literal types)。