所谓const限定符,指的是用于修饰某一不可变量的限定符。被const修饰的变量将具有为常量性,这将将告知编译器,该变量的值不能被修改。
int const n = 10;
const int n = 10; //等价的申明
n++; // Error 尝试修改被const限定符修饰的变量。
因为const类型一旦被创建了,就不能够再对其进行修改,因此const类型的变量在创建时就必须对其进行初始化。同样,const也能够修饰引用,被const修饰的引用称为常量引用。需要注意的是,常量引用可以修饰非常量值和常量值,但非常量引用不能够修饰常量值。
const size_t arrsize = 100;
const size_t & refarrsize = arrsize; // 没问题,常量引用修饰常量值
size_t & refarrsize = arrsize; // Error,非常量引用修饰常量值
double salary;
const double & refsalary = salary; // 没问题,常量引用修饰非常量值
和引用一样,也可以令指针指向常量或非常量。指向常量的指针不能用于修改所指对象的值
int n = 45;
const int *pn = &n;
n = 50;
*pn = 100; // Error 不能使用指向常量的指针修改所指向对象的值
不仅如此,我们还可以令指针本身为常量或非常量的,只需要将const放在*和名称中间即可。
int n = 1000;
int * const pn = &n;
这里的pn就变成了一个const类型的指针,可以使用它改变n的值,但不能再让它指向其他的地址了。有了上面的概念,我们甚至可以定义一个指向常量类型的常量指针。
int n = 1000;
const int * const pn = &n;
为了方便区分指向常量的指针和常量指针,这里引入两个概念,即顶层const和底层const。顶层const表示指针本身是个常量,而底层const表示的是指针(或是引用)所指对象是一个常量。
int n = 10;
int * const pn2 = &n; // 顶层const
const int * pn1 = &n; // 底层const
const int & refn = n; // 底层const
const不仅仅只是用来定义常量,它最大的作用在于const能够修饰函数的参数,甚至能够修饰成员函数
使用const修饰函数的参数,可以保证在函数执行时,函数不会修改传入的参数的值,如果函数试图修改传入参数的值,编译器将会报告这个错误。因此在函数中合理的使用const修饰符能够避免我们错误的修改数据,毕竟编译时错误总是比运行时错误要好得多。下面展示const在函数参数中的使用
#include
using namespace std;
// 没错,同名函数其参数的底层const类型不同能够进行重载
void fun(const int & i) {
cout << "const-parameter function call" << endl;
// i += 100; // Error
}
void fun(int & i) {
cout << "non-const-parameter function call" << endl;
i += 100;
}
// 因此这里还能写成
//void fun(const int * i) {
// cout << "const-parameter function call" << endl;
//}
//void fun(int * i) {
// cout << "non-const-parameter function call" << endl;
//}
int main() {
int i = 100;
fun(i);
cout << "i: " << i << endl;
const int n = 100;
fun(n);
cout << "n: " << n << endl;
return 0;
}
输出:
non-const-parameter function call
i: 100
const-parameter function call
n: 200
使用const修饰的成员函数将不能修改类成员,传入参数是否可以修改取决于参数是否被const限定符所修饰。下面展示const在成员函数中的使用
#include
#include
using namespace std;
class Person {
private:
string name;
int age;
double salary;
public:
Person(string n, int a, double s);
void raiseSalary(double rate);
void show() const;
};
Person::Person(string n, int a, double s)
: name(n), age(a), salary(s){
}
// 这里修改了类成员salary,因此不能使用const修饰
void Person::raiseSalary(double rate) {
salary += salary * rate;
}
// 因为这个成员函数不需要修改类成员,所以我们将其声明为const的
void Person::show() const {
cout << "name: " << name
<< ", age: " << age
<< ", salary: " << salary
<< endl;
}
int main() {
Person p1("Jim", 36, 7800.5);
p1.show();
p1.raiseSalary(0.15);
p1.show();
return 0;
}
输出:
name: Jim, age: 36, salary: 7800.5
name: Jim, age: 36, salary: 8970.58
使用const修饰函数返回值,一般用于运算符的重载,如operator[]等。下面这段代码摘自SGI 2.9.1
reference operator[](size_type n)
{
return *(begin() + n); }
const_reference operator[](size_type n) const
{
return *(begin() + n); }
// 其中reference和const_reference定义为
typedef value_type& reference;
typedef const value_type& const_reference;