const用法
背景
在c++中不管是定义常量,还是在函数的参数列表中都经常会使用到const,虽然知道const修饰变量后表示不可以修改,但是经常还是会在具体的使用中出错,所以想要彻底的弄懂它。
关键知识点
介绍
**const
是一个关键字,用于声明一个变量为常量,这意味着一旦被赋值后,其值就不能被改变。在C++中,const
**可以用来声明常量变量、常量指针、指向常量的指针等,以确保它们指向的值或它们本身在程序运行过程中不被修改。
面临的问题
在软件开发的早期阶段,程序员经常面临因变量值被意外修改而导致的bug。为了解决这个问题,**const
**关键字被引入,以便开发者可以明确地标记某些变量是不应该被修改的,从而提高代码的稳定性和可读性。
const修饰指针
- 常量指针:const 关键字位于指针类型之前,表示指针指向的内容不能被修改,但指针本身可以指向其他对象。
示例:
int a = 10;
const int* p1 = &a; // p1 指向 a,但不能修改 *p1 的值
*p1 = 20; // 错误,无法修改 *p1 的值
p1 = &b; // 可以修改 p1 指向的对象
- 指针常量:const 关键字位于指针类型之后,表示指针本身不能被修改,但指针指向的内容可以被修改。
示例:
C++
int a = 10, b = 20;
int* const p2 = &a; // p2 指向 a,且不能修改 p2
*p2 = 20; // 可以修改 *p2 的值
p2 = &b; // 错误,无法修改 p2 指向的对象
- 常量指针常量:const 关键字位于指针类型两侧,表示指针指向的内容和指针本身都不能被修改。
示例:
C++
int a = 10;
const int* const p3 = &a; // p3 指向 a,且不能修改 *p3 和 p3
*p3 = 20; // 错误,无法修改 *p3 的值
p3 = &b; // 错误,无法修改 p3 指向的对象
总结:
const 用于修饰指针时,可以根据其位置来判断其作用:
- 位于指针类型之前:常量指针,指向的内容不可修改
- 位于指针类型之后:指针常量,指针本身不可修改
- 位于指针类型两侧:常量指针常量,指针指向的内容和指针本身都不可修改
const 修饰方法
在 C++ 中,const
关键字可以用于修饰类的方法。这种方法被称为常量成员函数。常量成员函数不会修改对象的状态,也就是说,它不能修改任何成员变量(除非它们是用 mutable
关键字声明的)和调用非 const
的成员函数。
声明及定义
class MyClass {
public:
// 常量成员函数声明
int getValue() const;
private:
int value;
};
// 常量成员函数定义
int MyClass::getValue() const {
return value;
}
类成员常量
class MyClass {
public:
const int myConst;
MyClass(int val) : myConst(val) {
// myConst must be initialized in the initializer list.
}
};
c++中常量该怎么定义?
在C++中,常量可以通过**const
**关键字声明和定义,以确保其值在程序执行期间不被修改。下面是一些声明和定义常量的基本方法:
1. 基本类型的常量
对于基本数据类型(如整数、浮点数等),可以直接在变量声明时使用**const
**关键字来创建常量。
const int MAX_USERS = 100;
const double PI = 3.14159;
2. 指针常量
对于指针,**const
的使用稍微复杂一些,因为它可以用来声明指向常量的指针或者常量指针,这取决于const
**关键字的位置。
- 指向常量的指针(指针可以改变,指向的值不能改变):
const int* ptrToConst;
- 常量指针(指针不能改变,指向的值可以改变):
int* const constPtr;
- 指向常量的常量指针(指针和指向的值都不能改变):
const int* const constPtrToConst;
3. 类成员常量
在类中,可以使用**const
**来声明常量成员变量。这通常在类的构造函数初始化列表中赋值。
class MyClass {
public:
const int myConst;
MyClass(int val) : myConst(val) {
// myConst must be initialized in the initializer list.
}
};
4. 枚举常量
枚举(Enumeration)是一种定义在类中的常量集合,它是固定的,不能改变。
enum class Colors {
Red,
Green,
Blue
};
5. constexpr
常量
C++11引入了**constexpr
**关键字,用于编译时常量的声明,这可以用于变量、函数和类构造函数,以提高程序的效率。
constexpr int getArraySize() {
return 32;
}
constexpr int arraySize = getArraySize();
int myArray[arraySize];
使用**constexpr
**声明的函数必须满足特定条件,使得它们在编译时就能被求值。
注意事项
- 使用**
const
**声明的常量必须在声明时初始化。 - **
const
和constexpr
的主要区别在于constexpr
**用于那些必须在编译时就确定值的表达式。 - 类中的**
const
成员函数表示该函数不会修改任何成员变量(除了那些被声明为mutable
**的成员变量)。
通过这些方法,你可以在C++中有效地声明和定义常量,以提高代码的可读性和维护性。
constexpr和const有什么区别?
**constexpr
和const
**在C++中都用于声明常量,但它们的用途和含义有所不同。下面是它们之间的主要区别:
1. 编译时常量 vs 运行时常量
const
:用于声明一个值不可变的常量。**const
**可以在编译时或运行时初始化,这意味着它的值可以在编译时已知,也可以在运行时才确定。constexpr
:引入于C++11,用于声明一个必须在编译时就确定其值的表达式。这使得**constexpr
**非常适合定义编译时常量和函数,可以在编译时进行计算和检查。
2. 用途
const
:广泛用于声明各种类型的常量,包括对象、基本数据类型、指针等,其值在声明后不可更改。constexpr
:用于优化程序,通过在编译时计算表达式值来减少运行时的计算量。**constexpr
**适用于函数、对象构造函数以及简单的数值计算。
3. 函数和构造函数
const
:不能用于函数或构造函数的声明。constexpr
:可以用于函数和构造函数,要求函数体中的操作和返回值都必须是编译时可确定的。这允许在编译时进行函数调用和对象创建。
4. 存储位置
const
:可以用于静态存储期(如全局常量)和自动存储期(如局部常量)的对象。它不强制要求变量必须在编译时有确定的值。constexpr
:虽然**constexpr
**变量通常存储在程序的只读存储段中,但关键是它们必须在编译时就能被求值。
5. 类型限制
const
:几乎可以用于任何类型的变量,不要求变量类型在编译时可知。constexpr
:要求变量或函数的类型必须是字面类型(Literal Type),这意味着类型必须具有至少一个**constexpr
**构造函数,从而能在编译时被构造或计算。
示例
const
示例:
const int maxUsers = 100; // 运行时常量
constexpr
示例:
constexpr int getMaxUsers() {
return 100; // 编译时常量
}
总结
**const
和constexpr
都是用于声明常量的关键字,但constexpr
的引入是为了在编译时进行更多的计算,从而优化程序性能。constexpr
适用于那些可以在编译时完全确定的场景,而const
**更加通用,适用于运行时和编译时的常量声明。