c++中的const
共用数据的保护问题:
private保护数据只能用于类内,但是类中所有的成员函数都可以对private数据进行操作,所以很容易出现误操作。这时候就需要const。
const常变量 常对象 常函数
const既要使数据能在一定范围内共享,又要保证它不被任意修改。
常变量 :程序运行过程中不能随意修改,所以声明常变量的时候一定要同时初始化。
常对象:凡是希望保证数据成员不被改变的对象,可以声明为常对象。
常对象中的所有数据成员的值都不能被修改,即使用调用成员函数也不可以修改,否则就是错的。
例如:
const Time t1(10,10,10);
t1.set_time(20,20,20);
上面的程序就是错的,因为第二步中想借助于成员函数修改常对象中的数据成员。
常对象的两种等价的定义形式:
类名const 对象名[(实参表列)]
const类名 对象名 [(实参表列)]
常对象在定义的时候必须要有初值,因为常对象定义了之后就不可以随便更改了。也就是常对象中的数据成员为常变量且必须要有初值。初值
也就是数据成员的初始。这是通过构造函数赋值的。也就是说只要定义常对象就一定要执行构造函数。
常对象成员------------常成员函数
要引用常对象中的数据成员,需要将该成员函数声明为const型函数:常成员函数。
const是函数类型的一部分,也就是说在成员函数的声明和定义的时候都要指定const类型,举一个例子:
class Time
{
public:
void show_time() const;
};
void Time::show_time() const
{
}
需要注意的是:常成员函数可以访问常对象中的数据成员,但不允许修改常对象中数据成员的值。
如果程序运行过程中出现discards qualifiers错误,那么大部分情况下都是const使用不当造成的。
常对象成员-----------常数据成员
常数据成员用const声明,限定其值不能改变。
常数据成员的初始化只能通过构造函数的参数初始化表对常数据成员进行初始化。千万不能
在构造函数中用赋值的方法对常数据成员初始化。因为这样就违背了常数据成员的定义,常数据成员不能
被随意修改,也就是不能被赋值。不能用成员函数改变常数据成员的值。
和常对象进行对比可知,常对象的数据成员都是常数据成员。也就是说常对象中的所有数据成员都不能随意被赋值修改,也不能被非const成员函数访问。
常对象中的成员函数未加const,编译系统认为其实非const成员函数。当然常对象中的数据成员都是常变量。
从const的角度,成员函数对数据成员的访问规则:之所以const成员函数不能改标数据成员的值是因为既然函数已经为
const类型了,那么在该函数中就不能发生任何的数据成员的值的改变。
对常对象修改的限制:
如果一个对象被声明为常对象,则不能调用该对象的非const型的成员函数(除了由系统自动调用的隐式的构造函数和析构函数)
效果:
编译系统只检查函数的声明,只要发现调用了常对象的成员函数,而且该函数未被声明为const,就报错。
防止函数修改常对象中数据成员的值。
用常成员函数引用常变量。
设计策略:
如果在一个类中,有些数据成员的值允许改变,另一些数据成员的值不能改变,则
将一部分数据成员声明为const,以保证其值不被改变,用非const的成员函数引用和修改非const数据成员的值。
如果要求所有的数据成员的值都不允许改变
将所有数据成员声明为const(但是这样比较麻烦),或将对象声明为xonst(常对象),用const成员函数引用数据成员
如果已经定义一个常对象,为访问对象中的数据成员
将常对象中国的所有成员函数都声明为const成员函数,但应确保在函数中不修改对象中的数据成员,否则会报错的。
如果一个类中的大多数数据成员都应该不能被修改(const),只有一小部分数据需要可以被修改,那么可以将对象声明为常对象,同时需要被修改的数据成员声明为mutable类型。这样改数据成员就是可变的数据成员,可以用const成员函数修改其值。
指向对象的“常”指针:(常用于一个指针固定与一个对象联系) 类名 *const 变量名
将指针变量声明为const型,指针值始终保持为其初值,不能改变。
指针值不可变。指针指向的值是否可变,取决于指向的对象。如果对象是常对象,
那么里面的值不能变;否则,如果对象中有常数据成员,那么常数据成员不可变。将常指针作为函数的形参,目的是
不允许在函数执行过程中改变指针变量的值。
指向常变量的指针变量:
指针变量本身的值可变,指针指向的值不可改变。
定义形式有两种,分别为 const 类名 *变量名 类型名const*变量名。举个例子如下:
const char c[]="hello";//c数组名字,表示的也是数组首地址
const char *pt=c;//指向了常变量的指针指向常变量
char *pt=c;//错误,只有指向常变量的指针才能指向常变量。
如果一个变量已经被声明为常变量/对象,只能用指向常变量/对象的指针指向它,而不能用指向非const型变量/对象的指针去指向它。
指向常变量的指针变量可以指向未被声明为const的变量,但不能通过此const指针变量改变该变量的值。例如:
char c1='a';
const char *p;
p=&c1;//合法,指向常变量的指针可以指向非const变量
*p='b';//不合法,不能用指向常变量的指针改变变量的值
c1='b';//合法,c1不是常变量
指向常对象的指针变量:指针变量本身的值可变,指针指向的值不可改变。
定义指向常对象的指针变量的一般形式为:
const 类名*变量名 或者 类名const*变量名
例如:
const Time t1(10,12,15);
Time const*pt=&t1;//pt指向了常对象
pt->set_time(20,20,20);//错误,指针变量pt指向的是常对象,不能通过pt来改变其值
如果一个对象已被声明为常对象,只能用指向常对象的指针指向它,而不能用指向非const型变量/对象的指针去指向它。
指向常对象的指针变量可以指向未被声明为const的对象,但不能通过此指针变量改变该对象的值。例子:
Time t2;
Time const*pt=&t2;//可以用指向常变量的指针指向非const变量
pt->set_time(20,20,20);//错误,尽管t2.set_time(20,20,20)可以
原因在于既然pt是指向常对象的指针,那么用在这里的时候t2就已经被看作常对象了,所以不可以改变其值。
指向常对象的指针最常用于函数的形参,以保护形参指针所指向的对象在函数执行过程中不被修改。具体做法为:
当希望在调用函数时对象的值不被修改,就应当吧形参定义为指向常对象的指针变量,同时用对象的地址作为实参(对象可以是const或者非const型)。
指向const对象的指针--形参--实参
上面的表格中,(3)是最常用的,使用的结果是限制其他地方可以修改,但是函数内部不可以修改对象中的数据。
对象的常引用:
一个变量的引用就是变量的别名。
变量名和引用名都指向同一段内存单元。
函数的形式参数可以是对象的引用。如果不希望在函数中修改实参的值,可以将形参声明为常引用。例如:
void fun(const Time &);
void dosomething(const Test &r)
{
r.setX(5);//非法
r.printxy();
}
提倡:用常引用作函数参数的优势:
1. 这样既能保证数据安全,使数据不被随意修改;
2. 在调用函数时又不必建立实参的拷贝,可以提高程序运行效率。(引用是复制,占用同样的存储空间,不必另外分配存储空间)。比指针传值效率还要高。