CONST
一、符号常量
声明: const 类型说明符 常量名 = 常量值; const float PI = 3.1415927; //可以交换const与float的位置
符号常量在声明时一定要赋值,而在程序中间不能改变其值。注:const与“类型说明符“可以互换,即
const int a = 5; int const a = 5; //此两者等同
二、常对象及其常成员
2.1、常对象
声明: const 类型说明符 对象名; const Point p1(2,3); //可以交换const与Point的位置
常对象必须时这样的对象:它的数据成员值在对象的整个生存期间内不能被改变。也就是说,常对象必须进行初始化,而且不能被更新。
注:const与“类型说明符”也可以互换,但是人们更习惯于把const写在前面,即
const Point p1(2,3); Point const p2(3,4); //此两者等同
2.2常成员函数
声明: 类型说明符 函数名(参数表)const; void print()const; //定义 void print()const{ cout<<r1<<";"<<r2<<endl; }
- const是函数类型的一个组成部分,因此在函数的定义部分也要带const关键字。
- 如果将一个对象声明为常对象,则通过该常对象只能调用它的常成员函数,而不能调用其它成员函数(这就是C++从语法机制上对常对象的保护,也是常对象唯一的对外接口方式)。
- 无论是否通过常对象调用常成员函数,在常成员函数调用期间,目的对象都被视同为常对象,因此常成员函数不能更新目的对象的数据成员,也不能针对目的对象调用该类中没有用const修饰的成员函数(这就保证了在常成员函数中不会更改目的对象的数据成员的值)。
- const关键字可以用于对重载函数的区分。例如,如果在类中这样声明,这是对print的有效重载。
//有效重载。非const对象调用该函数,编译器将选择最近的重载函数--不带cons关键字的函数 void print(); void print()const;
习惯:在适当的地方使用const关键字,是能够提高程序质量的一个好习惯。对于无需改变对象状态的成员函数,都应当使用const。
2.3常数据成员
声明: private: const int a; //可以交换const与int的位置
就像一般数据一样,类的成员数据也可以是常量,使用const说明的数据成员为常数据成员。
- 如果在一个类中说明常数据成员,那么任何函数中都不能对该成员赋值。
- 构造函数对该数据成员进行初始化,就只能通过初始化列表。
static const int b; //静态常数据成员 const int A::b = 10 //静态常数据成员在类外说明和初始化 //注:之所以类的静态数据成员需要在类定义之外再加以定义,十四因为需要以这种方式专门为它们分配空间。非静态数据成员无需以此方式定义,因为它们的空间是与他们所属对象的空间同时分配的。 //在类外定义静态数据成员时无须加关键字static static int count; int Point::count = 0;
三、常引用
定义: const 类型说明符 & 引用名; const Point &p1; //可以交换const和Point的位置
- 常引用所引用的对象不能被更新。
- 如果用常引用作形参,便不会意外地发生对实参的更改。
- 非const的引用只能绑定到普通的对象,而不能绑定到常对象,但常引用可以绑定到常对象。
- 一个常对象,无论是绑定到一个普通的对象还是常对象,通过该引用访问该对象时,都只能把该对象当作常对象。
- 对于基本数据类型的引用,则不能为数据赋值。对于类类型的引用,则不能修改它的数据成员,也不能调用它的非const的成员函数。
习惯:对于在汉书中无需改变其值的参数,不宜使用普通引用方式传递,因为那会使得常对象无法被传入,采用传值方式或者传递引用得方式可避免这一问题。对于大对象来说,传值耗时较多,因此传递常引用为宜。复制构造函数得参数一般也宜采用常引用传递。
四、const与指针
4.1、指向常量的指针(不能通过指针来改变所指对象的值)
const int *p1 = &a; //指向常量的指针。 int b; p1 = &b; //正确,p1本省的值可以改变 *p1 = 1; //错误,不能通过p1改变所指的对象。但是a的值可以通过自己来改变,例如可以使用 a = 10; 另:const与int可以互换,语义相同 int const *p1 = &a; //与上面声明是等同的。
使用指向常量的指针,可以确保指针所指向的常量不被意外更改。如果用一般指针存放常量的指针,编译器就不能确保指针所指的对象不被更改。
4.2、指针类型的常量(指针本身不能被改变)
int * const p2 = &a; p2 = &b; //错误,p2是指针常量,值不能被改变。 *pe = 6; //正确,p2所指向的内容能通过指针来改变。
五、易混淆的地方
1、const与指针
常量与指针放在一起很容易让人迷惑。对于常量指针和指针常量也不是所有学习c++的人全都能说清的。例如:
const int *a1 = 3; int const *a2 = 4; int* const a3 = 5;
上面两个表达式中,最易混淆的就是const到底修饰的是阵阵还是指针指向的区域?其实,我们只要记住:const指对它左边的东西起作用,唯一的例外就是const本身就是最左边的修饰符,那么它才会对右边的东西起作用。根据这个判断,a1应该是常量指针(即指向常量的指针,不能通过a1来修改它所指向的内容);而a2应该是指针常量(即m2中所存的地址不能被改变)。
当然,还可以从右向左读得方式记忆:
a1(a2) is a pointer to const int. 故*a1的内容不可以改变,但是a1可以指向别的int。
a3 is a const pointer to int. 故a2不能指向别的变量,但可以修改其指向的int的内容。
2、const 修饰函数传入参数
将函数传入参数声明为const,以指明使用这种参数是为了效率,并且不想让调用函数改变对象的值。将指针参数声明为const,函数将不修改这个参数所指向的对象。
void Fun( const A *in); //修饰指针型为传入参数 void Fun( const A &in); //修饰引用型为传入参数