因为程序中各种形式的数据共享,在不同程度上破坏了数据的安全性。引入常类型的目的是,为了保证数据共享又防止数据被改动。
常类型是指使用类型修饰符 const 说明的类型,常类型的变量或对象成员的值在程序运行期间是不可改变的。
本文将从三方面入手:常引用、常对象和常对象成员。
一、常引用
- 常引用: 在说明引用时用 const 修饰的引用。
- 如果用 常引用作形参,便不会产生对实参的不希望的更改。
- 常引用的说明形式:
const 类型 &引用名;
例如:
int a=5;
const int &b=a;
其中,b 是一个常引用,它所引用的对象不允许更改。如果出现:b=22;
则非法。
例 1:常引用作函数参数。
在实际应用中,常引用往往用来作函数的形参,这样的参数称为 常参数。
用常引用作形参,能够避免对实参的更改,保证数据的安全。
#include<iostream>
using namespace std;
int add(const int &i,const int &j); //函数 add 的形参是常引用
int main(){
int a=20;
int b=30;
cout<<a<<"+"<<b<<"="<<add(a,b)<<endl;
a=15;
b=50;
cout<<a<<"+"<<b<<"="<<add(a,b)<<endl;
return 0;
}
int add(const int &i,const int &j){
//i=i+50; //不允许改变 i 的值,error是 assignment of read-only reference 'i' 即 给只读引用值'i'赋值出现错误
return i+j;
}
二、常对象
- 常对象:在说明对象时用 const 修饰。
- 常对象的数据成员值在对象的整个生存期内不能被改变。
- 常对象的说明形式:
类名 const 对象名[(参数表)];
或者
const 类名 对象名[(参数表)]
在定义对象时必须进行初始化,而且不能被更新。
例 2:常对象 和 非 常对象 的比较
#include<iostream>
using namespace std;
class Sample{
public:
int m;
Sample(int i,int j){
m=i;
n=j;
}
void setvalue(int i){
n=i;
}
void display(){
cout<<"m="<<m<<endl;
cout<<"n="<<n<<endl;
}
private:
int n;
};
int main(){
Sample a(10,20);
a.setvalue(40);
a.m=30;
a.display();
return 0;
}
在例 2 中,对象 a 是一个普通的对象,而不是常对象,执行结果为:
若将上述的对象 a 定义为常对象,主函数修改一下:
int main(){
const Sample a(10,20); //a 是常对象,而不是普通对象
a.setvalue(40); //错误:不允许改变常对象的数据成员值
a.m=30; //错误:不允许改变常对象的数据成员值
a.display(); //错误:不允许常对象调用普通的成员函数
return 0;
}
则会出现三处错误(要格外注意,第三处错误,不允许常对象调用普通的成员函数)。
三、常对象成员
1、常数据成员
- 类的数据成员可以是常量或常引用,使用 const 说明的数据成员称为 常数据成员。
- 如果在一个类中说明了常数据成员,那么构造函数就只能通过成员初始化列表对该数据成员进行初始化,在构造函数的函数体内对常数据成员赋初值也是非法的,而且其他任何函数都不能对该成员赋值。
- 一旦对某对象的常数据成员初始化后,该数据成员的值是不能改变的,但不同对象中的该数据成员的值可以是不同的(在定义对象时给出)。
例 4:常数据成员的使用。
#include<iostream>
using namespace std;
class Date{
public:
Date(int y,int m,int d);
void showDate();
private:
const int year; //常数据成员
const int month;
const int day;
};
Date::Date(int y,int m,int d):year(y),month(m),day(d){
}
void Date::showDate(){
cout<<year<<"."<<month<<"."<<day<<endl;
}
int main(){
Date date1(2018,11,25);
date1.showDate();
return 0;
}
2、常成员函数
- 在类中使用关键字 const 说明的成员函数为常成员函数。
- 常成员函数的说明格式如下:
类型说明符 函数名(参数表) const;
const是函数类型的一个组成部分,因此在声明和定义函数时都要有关键字 const,在调用时不必加 const。
例 5:常成员函数的使用(仔细看代码)。
#include<iostream>
using namespace std;
class Date{
public:
Date(int y,int m,int d);
void showDate(); //声明普通的成员函数 showDate
void showDate() const; //声明常成员函数 showDate
private:
int year;
int month;
int day;
};
Date::Date(int y,int m,int d):year(y),month(m),day(d){
}
void Date::showDate(){
cout<<"showDate1:"<<endl;
cout<<year<<"."<<month<<"."<<day<<endl;
}
void Date::showDate() const{
cout<<"showDate2:"<<endl;
cout<<year<<"."<<month<<"."<<day<<endl;
}
int main(){
Date date1(2018,11,25); //定义普通对象 date1
date1.showDate();
const Date date2(2018,9,28); //定义常对象 date2
date2.showDate();
return 0;
}
执行结果:
在例 5中类 Date 说明了两个同名的成员函数 showDate,一个是普通的成员函数,另一个是常成员函数,它们是重载的(关键字 const 可以被用于区分重载函数)。
在主函数中说明了两个对象 date1 和 date2,其中对象 date2 是常对象。通过对象 date1 调用的是没有用 const 修饰的成员函数 showDate,而通过对象 date2 调用的是用 const 修饰的常成员函数 showDate。
说明注意:
(1)常成员函数可以访问常数据成员,也可以访问普通数据成员。
数据成员 | 普通成员函数 | 常成员函数 |
---|---|---|
普通数据成员 | 可以访问,也可以改变值 | 可以访问,但不可以改变 |
常数据成员 | 可以访问,但不可以改变值 | 可以访问,但不可以改变 |
常对象的数据成员 | 不允许访问和改变值 | 可以访问,但不可以改变 |
(2)如果将一个对象说明为常对象,则通过该对象只能调用它的常成员函数,而不能调用普通的成员函数。所以说,常成员函数是常对象唯一的对外接口,这是C++从语法机制上对常对象的保护。
(3)常成员函数不能更新对象的数据成员,也不能调用该类中的普通成员函数,这就保证了在常成员函数中绝对不会更新数据成员的值。