本文主要讨论c++中const修饰的常对象与没有const修饰的普通对象中的成员函数返回值的常性问题,其中成员函数包括有const修饰和没有const修饰(因为const在成员函数中能形成重载所以能并存),成员变量包括普通变量,指针变量与对象
1 类中的成员变量为普通变量
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
class Base
{
public:
Base(int d = 0):data(d){}
~Base(){}
// 返回值为成员数据的值,有const形成常函数重载
int GetVal() { return data;}
int GetVal()const{ return data; }
// 返回值为成员数据的引用,有const形成常函数重载
int& GetRef(){ return data; }
// 常函数不能修改data的值,以引用返回时为保证data引用空间不被修改,
// 要用const修饰返回值
const int& GetRef()const{ return data; }
// 返回值为成员数据的地址,有const形成常函数重载
int* GetPtr(){ return &data; }
// 常函数不能修改data的值,返回data的地址时为保证data的值不被修改,
// 要用const修饰 *,即不能通过指针的解引用去改变data的值
const int* GetPtr()const{ return &data; }
private:
int data;
};
int main()
{
Base base1(10); // 普通对象
const Base base2(100); // 常对象
int a1 = base1.GetVal();
// base1.GetVal()返回的是一个临时对象,具有常性,即const int tmp
// 当用引用绑定这个具有常性的空间时,要用const修饰引用
const int &aref1 = base1.GetVal();
int a2 = base2.GetVal();
// base2.GetVal()返回的是一个临时对象,具有常性,即const int tmp
// 当用引用绑定这个具有常性的空间时,要用const修饰引用
const int &aref2 = base2.GetVal();
// 直接返回非常对象的引用,没有常性
int b1 = base1.GetRef();
int &bref1 = base1.GetRef();
const int &bref1_ = base1.GetRef();
int b2 = base2.GetRef();
// 直接返回常对象的引用,有常性,要用const修饰
const int &bref2 = base2.GetRef();
int* p1 = base1.GetPtr();
// 返回一个临时的指针变量p,具有常性,即 int *const tmp;
// 要用const修饰引用指针
int* const &pref1 = base1.GetPtr();
// 常对象的数据成员具有常性,不能通过指针改变其值
const int *p2 = base2.GetPtr();
// 常对象返回的临时指针,具有双重常性,用引用绑定时,要用双重const修饰
const int* const &pref2 = base2.GetPtr();
system("pause");
return 0;
}
2 类中的成员变量为指针变量
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
class Base
{
public:
Base(int d = 0) :ptr(new int(d)){}
~Base(){}
int* GetVal() { return ptr; }
int* GetVal()const{ return ptr; }
int* & GetRef(){ return ptr; }
// 返回一个指针,但是指针是以引用的方式返回
// 由于是const方法,要用const修饰引用
int* const & GetRef()const{ return ptr; }
int** GetPtr(){ return &ptr; }
// ptr是指针,且为常量,const修饰的是二级指针的值
int*const* GetPtr()const{ return &ptr; }
private:
int *ptr;
};
int main()
{
Base base1(10);
const Base base2(100);
int* p1 = base1.GetVal();
int* const &pref1 = base1.GetVal();
int* p2 = base2.GetVal();
int* const &pref2 = base1.GetVal();
int* refp1 = base1.GetRef();
int* &refp1_ = base1.GetRef();
int* refp2 = base2.GetRef();
int* const &refp2_ = base2.GetRef();
int** pd1 = base1.GetPtr();
// pdref1绑定临时变量的空间,有常性
int** const &pdref1 = base1.GetPtr();
int*const* pd2 = base2.GetPtr();
// *pdref2 = ptr 有常性
// pdref2绑定临时变量的空间,有常性
int*const* const &pdref2 = base1.GetPtr();
system("pause");
return 0;
}
3 类中的成员变量为对象
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
class Int
{
public:
Int(int d = 0) :data(d){}
~Int(){}
private:
int data;
};
class Base
{
public:
Base(int d = 0) :data(d){}
~Base(){}
Int GetVal(){ return data; }
Int GetVal()const{ return data; }
Int& GetRef(){ return data; }
const Int& GetRef()const { return data; }
Int* GetPtr(){ return &data; }
const Int* GetPtr()const{ return &data; }
private:
Int data;
};
int main()
{
Base base1(10);
const Base base2(100);
Int a1 = base1.GetVal();
// 区别于类中成员为内置类型,当成员为对象时,调用拷贝构造函数
// 这里不会返回临时对象,不具有常性
Int &aref1 = base1.GetVal();
Int a2 = base2.GetVal();
// 区别于类中成员为内置类型,当成员为对象时,调用拷贝构造函数
// 这里不会返回临时对象,不具有常性
Int &aref2 = base2.GetVal();
Int b1 = base1.GetRef();
Int& refb1 = base1.GetRef();
Int b2 = base2.GetRef();
const Int& refb2 = base2.GetRef();
Int *p1 = base1.GetPtr();
Int* const &pref1 = base1.GetPtr();
const Int* p2 = base2.GetPtr();
const Int* const &pref2 = base2.GetPtr();
system("pause");
return 0;
}
总结:判断返回值是否具有常性,要注意一下几点
1、const对象的成员数据具有常性
2、当返回指针或引用时,要考虑指针所指向空间的常性和引用所绑定空间的常性
3、const成员方法不能修改成员变量的值
4、以临时变量返回具有常性
5、当返回对象时,调用的是拷贝构造函数,不会返回临时变量