1. 常量
在C++中,常量(Constants)是指在程序执行期间不会改变其值的变量。常量是一种值被设置后不能被修改的标识符。使用关键字 const
可以声明常量,并将其与一个特定的值绑定。
1.1 常量的使用场景
- 防止数据被修改:通过将变量声明为常量,可以确保其值在初始化后不会被修改,从而增加程序的可靠性和安全性。特别是在函数中传递参数时,将参数声明为常量可以避免对参数值的意外修改。
void processData(const int value) {
// value = 10; // 错误,常量不可修改
// 处理数据
}
- 提高程序可读性:通过将常量定义为具有描述性的名称,可以提高程序的可读性和可维护性。这样,在代码中使用常量的地方,可以直接使用具有描述性的名称,而无需记住具体的数值或字符串。
const int MAX_COUNT = 100;
for (int i = 0; i < MAX_COUNT; ++i) {
// 循环操作
}
- 避免硬编码:常量的使用可以避免在代码中直接使用数值或字符串,从而减少硬编码。这样,如果需要修改常量的值,只需要修改常量的定义,而无需在代码中逐个修改。
const float PI = 3.14159;
float radius = 5.0;
float area = PI * radius * radius;
- 优化代码:在某些情况下,编译器可以利用常量的值进行优化,例如在编译时进行常量折叠(Constant Folding)和循环展开(Loop Unrolling),从而提高程序的执行效率。
const int LOOP_COUNT = 100;
for (int i = 0; i < LOOP_COUNT; ++i) {
// 循环操作
}
1.2 使用常量时要遵循规则:
- 常量必须在声明时进行初始化,并且初始化后不能再修改其值。
- 常量命名通常使用全大写形式,并采用下划线分隔单词(例如MAX_SIZE)。
- 使用常量时应该考虑其作用域和生命周期,确保其在所需范围内有效。
- 常量可以用于各种数据类型,包括基本类型、对象和指针。
常量在代码中起到了提高可读性、安全性和性能的作用,并且可以约束参数类型。合理使用常量可以使程序更加健壮和可维护。
2. 常指针
参考 c++ 常量指针与指针常量
常指针(const pointer)是指一个指针变量,它所指向的内存地址数据不可修改。
2.1 使用场景
- 保护对象的值不被修改:通过将指针声明为常指针,可以确保所指向的对象的值不被修改。这对于传递指针给其他函数或共享指针时很有用,可以防止函数或其他部分意外地修改对象的值。
int value = 10;
const int* ptr = &value;
// *ptr = 20; // 错误,常指针不能修改所指向的对象的值
- 传递指针给只读函数:常指针可以用于传递指针给只读函数,这样可以确保函数内部不会修改所指向的对象的值,增加程序的安全性。
void printData(const int* ptr) {
// *ptr = 20; // 错误,只读函数不能修改所指向的对象的值
std::cout << "Data: " << *ptr << std::endl;
}
- 与常对象配合使用:常指针可以与常对象配合使用,用于指向不可修改的对象。这样可以确保指针不会被用于修改对象的值。
完整代码:
#include <iostream>
void printData(const int* ptr) {
std::cout << "Data: " << *ptr << std::endl;
}
int main() {
int value = 42;
const int* ptr = &value;
printData(ptr);
return 0;
}
3. 常函数
常函数(常成员函数)(const member function)是指在函数声明和定义中使用 const 关键字修饰的成员函数。常函数承诺不会修改对象的任何成员变量,它只能读取成员变量的值,但不能修改它们。这样可以确保在常对象上调用常函数时,对象的状态不会发生变化。
3.1 常函数特点
- 常函数不会修改对象的状态:常函数保证在其内部不会对类的成员变量进行修改操作。
- 常函数可以被常对象调用:常对象是指被声明为
const
的对象,在其上只能调用常成员函数。 - 常函数可以被非常对象调用:非常对象上既可以调用常成员函数,也可以调用非常成员函数。
代码:
#include <iostream>
#include <string>
using namespace std;
class Rectangle {
private:
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
// 非常成员函数
void setWidth(int w) {
width = w;
// this : Rectangle *
}
// 声明为常成员函数
int getWidth() const {
return width;
// this : const Rectangle *
}
};
常函数只能去读成员的数据,不能修改成员的值;
常函数不能调用普通的函数,只能调用常函数;
普通成员函数中的this指针 Rectangle *
,而常函数this指针是const Rectangle *
,就是常量指针,它所指向的内存地址数据不可修改
3.2 使用场景
- 保证数据成员不被意外修改:如果你希望某些成员变量在对象被视为"只读"时不能修改,你可以将相关操作定义为常成员函数。
- 提供只读访问接口:有时候你希望提供一些只读方法来获取类中的数据,而不允许通过这些方法进行修改操作。这种情况下,你可以将这些方法声明为常成员函数。
4. 常对象
常对象(常量对象)(Constant object)是指通过使用 const 关键字修饰的对象。常对象的值在创建后不能被修改,它的成员变量和成员函数都被视为常量,并且只能调用常函数。
代码:
#include <iostream>
#include <string>
using namespace std;
class Rectangle {
private:
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
// 非常成员函数
void setWidth(int w) {
width = w;
// this : Rectangle *
}
// 声明为常成员函数
int getWidth() const {
return width;
// this : const Rectangle *
}
};
int main() {
Rectangle rect0(20, 5); // 非常对象
//非常对象上可以调用非常成员函数
rect0.setWidth(15);
//非常对象上可以调用常成员函数
int width0 = rect0.getWidth();
cout << "Width: " << width0 << endl;
const Rectangle rect(10, 5); // 常对象
// 调用常成员函数
int width = rect.getWidth();
cout << "Width: " << width << endl;
// 无法调用非常成员函数
// rect.setWidth(20); // 编译错误
return 0;
}
运行结果:
Width: 15
Width: 10
4.1 提示
如果想改某个变量的值,可以给某个变量加上 mutable
关键字,表示这个变量是可变的。
#include <iostream>
#include <string>
using namespace std;
class Rectangle {
public:
int width;
mutable int height;
Rectangle(int w, int h) : width(w), height(h) {}
// 非常成员函数
void setWidth(int w) {
width = w;
// this : Rectangle *
}
// 声明为常成员函数
int getWidth() const {
//width = 10
height = 30;
return width;
// this : const Rectangle *
}
};
int main() {
Rectangle rect0(20, 5); // 非常对象
//非常对象上可以调用非常成员函数
rect0.setWidth(15);
//非常对象上可以调用常成员函数
int width0 = rect0.getWidth();
cout << "Width: " << width0 << endl;
const Rectangle rect(10, 5); // 常对象
// 调用常成员函数
int width = rect.getWidth();
cout << "Width: " << width << endl;
rect.height =100;
// 无法调用非常成员函数
//rect.setWidth(20); // 编译错误
return 0;
}
把 height 声明为 mutable后 mutable int height;
不仅在常函数可以改变成员变量的值:
// 声明为常成员函数
int getWidth() const {
//width = 10
height = 30;
return width;
}
而且常对象也可以改变成员函数的值
const Rectangle rect(10, 5); // 常对象
// 调用常成员函数
int width = rect.getWidth();
cout << "Width: " << width << endl;
rect.height =100;
//rect.width = 200;
4.2 使用场景
-
数据保护:常对象用于保护数据不被修改。当某个对象的值在创建后不应该被改变时,可以将其声明为常对象,从而确保对象的值不会被意外修改。
-
代码安全性:常对象的使用可以提高代码的安全性。在多线程环境下,常对象可以防止并发访问导致的数据竞争和错误修改。此外,常对象还可以避免意外修改对象的值,增加代码的可靠性。