常对象
常对象是指该对象在其生命周期内,其所有的数据成员的值都不能被改变;定义对象时加上关键字const,该对象就是常对象,其一般形式如下:
类名 const 对象名[(实参类别)];
或者
const 类名 对象名[(实参类别)];
形如:const CComplex num;
需要特别说明的是:
1. 常对象只能调用常成员函数,不能调用普通成员函数 (除了隐式调用析构函数和构造函数),常成员函数是常对象的唯一对外接口;
2. 现在编译系统只检查函数的声明,只要发现调用了常对象的成员函数,而且该函数未被声明为const,编译阶段就报错;
3. 常对象在被定义时需要被初始化;
类设计源码:
class CComplex
{
public:
//普通构造函数
CComplex(int nReal, int nImag):m_nReal(nReal),m_nImag(nImag)
{
cout << "common constructor function" << endl;
}
int GetRealNum()
{
return m_nReal;
}
private:
int m_nReal;
int m_nImag;
};
//常对象
const CComplex num1(1,1);
//error:不能将“this”指针从“const CComplex”转换为“CComplex &”
int nReal = num1.GetRealNum();
编译错误的原因是,目前该函数还是普通函数,它可能会修改成员变量;为了常对象能调用GetRealNum函数,应该将该函数设计成常成员函数;
形如int GetRealNum() const;
常数据成员
如果我们希望在创建对象后,该对象的某个数据成员就保持不变,我们可以将这个数据成员设置为常数据成员;常数据成员只能通过构造函数初始化列表进行初始化,其他形式的函数均不能进行数据的赋值;
常成员函数
若将成员函数设置为常成员函数,则只能引用本类中的数据成员,而不能修改它;常成员函数可以引用const数据成员,也可以引用非const的数据成员;常成员函数的一般形式为:
类型名 函数名(形参列表) const
这里的const关键字是函数类型的一部分,在函数声明和函数定义时都要带const关键字,否则被编译器认为是不同的两个函数,但是在函数调用的时候不必带const;
形如:
//声明和定义一起实现
int GetRealNum() const
{
return m_nReal;
}
函数API设计总结
(1) 若我们定义了一个常对象,则指向这个常对象的指针变量或者对象引用也需要是const类型的;一般形式如下:
const 类型名* 指针变量名;
const 类型名& 引用名;
(2)常对象的唯一对外接口是常成员函数;
(3)为了节约时间开销和时间开销,一般将函数形参定义为指针或者引用类型;
(4)若不希望传入的实参对象被修改,应该将形参定义指向常对象的指针变量或者引用;
根据以上几点知识,我们进行类设计时,最好遵循以下两点结论:
1.将不涉及数据成员修改的函数定义为常成员函数;
形如: int GetRealNum() const
2.当发生函数调用时,希望传入的实参对象不被修改,应当将形参定义为const类型的指针或者引用;这个实参可以是const类型的,也可以是非const类型的,函数接口兼容性更加,形如:
static void TransByPointer(const CComplex* obj)
{
cout << "TransByPointer
" << endl;
}
static void TransByRefence(const CComplex& obj)
{
cout << "TransByRefence
" << endl;
}
下面给出const相关知识的具体调用说明:
数据成员 | 非const的普通成员函数 | const成员函数 |
---|---|---|
非const的普通数据成员 | 可以引用,也可以改变值 | 可以引用,但不可以改变值 |
const数据成员 | 可以引用,但不可以改变值 | 可以引用,但不可以改变值 |
const对象 | 不允许 | 可以引用,但不可以改变值 |