静态成员的使用让类的对象之间能共享数据,友元的使用破坏了类的封装性,却给了类的“朋友”对本类成员访问的特权。但是,有时候要求数据在能共享的前提下还不能被修改,也就是要实现数据的保护。
(一)常成员变量
const更加严格,也更加安全!
一般常量:
1)int const x=2; 等价于const int x=2;
int const a[3]={1,2,3];等价于 const int a[3]={1,2,3};
2)float x=4.56;
float是单精度浮点型数据,而4.56是双精度的数据,所以将4.56赋值给x不安全!
在类的成员定义中,使用修饰符const说明的成员变量成为常成员变量。常成员变量必须初始化,并且不能被修改,它是通过构造函数的成员初始化列表进行初始化的。
#include<iostream>
using namespace std;
class A
{
public:
A(int a);
void printf();
private:
const int a; //常成员变量a;
};
A::A(int i):a(i) //成员初始化列表对a进行初始化
{ }
void A::printf()
{
cout<<"a:"<<a<<endl;
}
int main()
{
A m(1);
m.printf();
return 0;
}
(二)常对象
常成员变量能够保证某个成员变量在程序运行过程中不被修改,若希望所有的成员变量都不被修改,则可以将对象声明为常对象。成员变量的值在整个生存期内不能被改变的对象称为常对象(也称为const对象),常对象必须进行初始化,而且不能被更新。
声明常对象的语法形式为:
类名 const 对象名;//或const 类名 对象名;
例如,有以下类的说明:
class A
{
public:
A(int i,int j){x=i;y=j:}
void set(int i,int j){x=i;y=j}
private:
int x,y;
};
以下语句中定义常对象a和普通对象b,C++规定:不能通过常对象调用普通成员函数!
A const a(3,4);
A b;
b.set(1,2); //正确
a.set(1,2); //错误
为什么常对象不能调用普通成员函数呢?
因为普通成员函数可能会修改常对象中成员变量的值。也就是说,如果一个对象被定义为成员对象,那么不能调用该对象的普通成员函数,但是系统可以隐含调用构造函数和析构函数。
注意:
有时因为编译需要,一定要修改常对象中某个成员变量的值,则可以将其声明为mutable。
例如:某个计算器变量count
mutable int count;
即将count声明为可变的成员变量,可以用声明为const的成员函数来修改它的值。
(三)常成员函数
既然常对象无法调用普通成员函数,那常对象中的成员变量该如何使用呢?做法是将该成员函数声明为const类型,即常成员函数(也称为const成员函数)。
方法为:
函数返回值类型 函数名(参数列表) const;
例如:
void set(int i,int j) const;
例:常对象和常成员函数的应用。
#include<iostream>
using namespace std;
class Circle
{
public:
Circle(int rr=0) //类的构造函数
{
r=rr;
}
double Get1() const //定义常成员函数
{
return r;
}
double Get2() //普通成员函数
{
return r;
}
private:
double r;
};
int main()
{
const Circle r1(3.3); //定义常对象
Circle r2; //定义普通对象
cout<<"r1:"<<r1.Get1()<<endl;
cout<<"r2:"<<r2.Get2()<<endl;
return 0;
}
注意:常成员函数可以访问常对象中的成员变量,但任然不能修改它们。
总结:
(1)类中如果一些成员变量需要保护,另一些成员变量不需要保护,就将需要保护的变量声明为const,以保证其值不会被改变。
(2)类中如果所有成元变量都需要保护,可以将所有成员变量都声明为const,本对象的任何成员函数都只能引用不能改变他们。或者将这些成员变量所属的对象声明为const,只让本对象的const成员函数引用,但不能改变。
(3)如果一个对象被定义成立常对象,只能调用类中的const成员函数,不能调用非const成员函数。
(4)常成员函数不能调用非const成员函数,因为这样有可能会修改成员变量的值。