前言
C++虽然采取了不少有效的措施(如设private保护)以增加数据的安全性,但是有些数据却往往是共享的,人们可以在不同的场合通过不同的途径访问同一个数据对象。有时在无意之中的误操作会改变有关数据的状况,而这是人们所不希望出现的。既要使数据能在一定范围内共享,又要保证它不被任意修改,这时可以使用const,即把有关的数据定义为常量。
常对象
在定义对象时指定对象为常对象。常对象必须要有初值,如:const Cat c(12,34); //c是常对象
这样,在所有的场合中,对象c中的所有成员的值都不能被修改。凡希望保证数据成员不被改变的对象,可以声明为常对象。
定义常对象的一般形式为:
类名 const 对象名[(实参表列)];
也可以把const写在最左面:
const 类名 对象名[(实参表列)];
二者等价。
我习惯使用第二种
如果一个对象被声明为常对象,则不能调用该对象的非const型的成员函数(除了由编译器自动调用的隐式的构造函数和析构函数)。
for example:
const Cat c(1,2); //定义常对象c
c.getter( ); //企图调用常对象c中的非const型成员函数,非法
这是为了防止这些函数会修改常对象中数据成员的值。
引用常对象中的数据成员很简单,只需将该成员函数声明为const即可。如:
void getter( ) const ; //将函数声明为const
这表示getter是一个const型函数,即常成员函数。
常成员函数可以访问常对象中的数据成员,但仍然不允许修改常对象中数据成员的值。有时在编程时有要求,一定要修改常对象中的某个数据成员的值,ANSI C++考虑到实际编程时的需要,对此作了特殊的处理,对该数据成员声明为mutable,如:
mutable int abc;
把abc声明为可变的数据成员,这样就可以用声明为const的成员函数来修改它的值。
常对象成员
可以将对象的成员声明为const,包括常数据成员和常成员函数。1) 常数据成员
其作用和用法与一般常变量相似,用关键字const来声明常数据成员。常数据成员的值是不能改变的。
有一点要注意: 只能通过构造函数的参数初始化表对常数据成员进行初始化。如在类体中定义了常数据成员def:
const int def; //声明def为常数据成员
不能采用在构造函数中对常数据成员赋初值的方法,下面的做法是非法的:
Cat::Cat(int p){
abc=p;
} // 非法
因为常数据成员是不能被赋值的。
在类外定义构造函数,应写成以下形式:
Cat::Cat(int p):abc(p){} //通过参数初始化表对常数据成员hour初始化
常对象的数据成员都是常数据成员,因此常对象的构造函数只能用参数初始化表对常数据成员进行初始化。
2) 常成员函数
前面已提到,一般的成员函数可以引用本类中的非const数据成员,也可以修改它们。如果将成员函数声明为常成员函数,则只能引用本类中的数据成员,而不能修改它们,例如只用于输出数据等。如
void getter( ) const ; //注意const的位置在函数名和括号之后
const是函数类型的一部分,在声明函数和定义函数时都要有const关键字,在调用时不必加const。常成员函数可以引用const数据成员,也可以引用非const的数据成员。const数据成员可以被const成员函数引用,也可以被非const的成员函数引用。具体情况可以用下表表示。
数据成员 | 非const成员函数 | const成员函数 |
---|---|---|
非const的数据成员 | 可以引用,也可以改变值 | 可以引用,但不可以改变值 |
const数据成员 | 可以引用,但不可以改变值 | 可以引用,但不可以改变值 |
const对象的数据成员 | 不允许 | 可以引用,但不可以改变值 |
那么怎样利用常成员函数呢?
- 如果在一个类中,有些数据成员的值允许改变,另一些数据成员的值不允许改变,则可以将一部分数据成员声明为const,以保证其值不被改变,可以用非const的成员函数引用这些数据成员的值,并修改非const数据成员的值。
- 如果要求所有的数据成员的值都不允许改变,则可以将所有的数据成员声明为const,或将对象声明为const(常对象),然后用const成员函数引用数据成员,这样起到“双保险”的作用,切实保证
- 如果已定义了一个常对象,只能调用其中的const成员函数,而不能调用非const成员函数(不论这些函数是否会修改对象中的数据)。这是为了保证数据的安全。如果需要访问对象中的数据成员,可将常对象中所有成员函数都声明为const成员函数,但应确保在函数中不修改对象中的数据成员。
不要误认为常对象中的成员函数都是常成员函数。常对象只保证其数据成员的值不被修改。如果在常对象中的成员函数未加const声明,编译系统把它作为非const成员函数处理。
===================================================================================================================================
华丽的分割线,更新一波,加一点关于const的内容,昨天晚上睡觉的时候,想起了关于const的另外一点知识,今天给补上,欢迎大家补充
const指针和const引用对于初学者来说是很头疼的一件事情,很容易混淆;特别是const指针,const的不同位置意思就不一样。
const指针
在C++11里面,const指针分为顶层const和底层const。顶层const是指针本身不可变,底层const是指针指向的value不可变;其实我感觉区分顶层和底层并不是很重要,比如给我们一行代码,我们只要可以区分的出,是指针不可变还是它指向的value不可变我觉得就ok了。下面我将举出顶层和底层const指针不同形似,帮助大家更好的理解它们
1、顶层const指针
int a=0;
int *const pa=&a;
//此时pa是顶层const,即pa本身不可以改变,但是指向的值是可以改变的
2、底层const指针
int a=0;
const int *pa1=&a;
int const *pa2=&a;
//上面的pa1和pa2都是底层const指针,即指针本身可以改变,但是它们指向的值不能被改变
需要注意的是,还有一种比较特殊的指针
int a=0;这两种指针可以认为是底层和顶层的综合,即指针本身不可改变,其指向的value也不能改变
cont int *const pa=&a;
int const *const pa2=&a;
const引用
int a=0;
const int b=1;
cont int &ra=a;
cont int &rb=b;
//ra是const引用,即ra、rb都是不可改变的,引用的类型必须要完全不一样,例如不能让double引用和int类型变量绑定在一起