这里的T指的是一种数据类型,可以是int、long、doule等基本数据类型,也可以是自己类型的类型class。单独的一个const你肯定知道指的是一个常量,但const与其他类型联合起来的众多变化,你是不是就糊涂了?下面我们一一来解析。
const T
定义一个常量,声明的同时必须进行初始化。一旦声明,这个值将不能被改变。
int i = 5;
const int constInt = 10;
const int constInt2 = i;
constInt = 20;
const int constInt3;
const T*
指向常量的指针,不能用于改变其所指向的对象的值。
const int i = 5;
const int i2 = 10;
const int* pInt = &i;
pInt = &i2;
const int* p2 = new int(8);
delete p2;
int nValue = 15;
const int * pConstInt = &nValue;
*pConstInt = 40;
const int* 与int* const的区别
指针本身就是一种对象,把指针定义为常量就是常量指针,也就是int* const的类型,也可以写成int *const,声明时必须初始化。
int nValue = 10;
int* const p = &nValue;
int *const p2 = &nValue;
const int* 指针指向的对象不可以改变,但指针本身的值可以改变;int* const 指针本身的值不可改变,但其指向的对象可以改变。
int nValue1 = 10;
int nValue2 = 20;
int* const constPoint = &nValue1;
*constPoint = 40;
const int nConstValue1 = 5;
const int nConstValue2 = 15;
const int* pPoint = &nConstValue1;
pPoint = &nConstValue2;
const int* const 是一个指向常量对象的常量指针,即不可以改变指针本身的值,也不可以改变指针指向的对象。
const int nConstValue1 = 5;
const int nConstValue2 = 15;
const int* const pPoint = &nConstValue1;
const T&
对常量(const)的引用,又称为常量引用,常量引用不能修改其邦定的对象。
int i = 5;
const int constInt = 10;
const int& rConstInt = constInt;
rConstInt = 5;
允许为一个常量引用邦定一个非常量对象、字面值,甚至是表达式;引用的类型与引用所指向的类型必须一致。
int i = 5;
int& rInt = i;
const int constInt = 10;
const int& rConstInt = constInt;
const int& rConstInt2 = rInt;
rInt = 30;
int i2 = 15;
const int& rConstInt3 = i2;
const int& rConstInt4 = i + i2;
i = 20;
const int& rConstInt5 = 50;
const T*&与T *const&
指向常量对象的指针的引用,这可以分两步来理解:1.const T*是指向常量的指针;2.const T*&指向常量的指针的引用。
const int nConstValue = 1;
const int nConstValue2 = 2;
const int* pConstValue = &nConstValue;
const int* pConstValue2 = &nConstValue2;
const int*& rpConstValue = pConstValue;
rpConstValue = pConstValue2;
int nValue = 5;
int nValue2 = 10;
int *const constPoint = &nValue;
int *const constPoint2 = &nValue2;
int *const &rpConstPoint = constPoint;
*rpConstPoint = 20;
在函数中的应用
我们直接从需求出来,假设有这样一个数据结构:
typedef struct __Data
{
int value;
public:
__Data()
:value(0){}
}Data;
1.希望传入一个对象,又不想让函数体修改这个对象。
方式<1>
void Dealwith(const Data& data)
{
cout << data.value << endl;
//data.value = 5; //错误,data是常量引用,不能改变其邦定的对象
}
这种方式还有一个好处是只有在调用函数的时候会邦定对象,传递的是对象的引用,而不是对象,减少函数调用时对象赋值的花销。
方式<2>
void Dealwith(const Data* pData)
{
cout << pData->value << endl;
}
这种方式与void Dealwith(const Data& data)的功能相同
方式<3>
Data g_data(20);
void Dealwith(const Data*& pData)
{
cout << pData->value << endl;
pData = &g_data;
}
调用如下:
Data d(10);
const Data* pData = &d;
Dealwith(pData);
cout << pData->value << endl;
这种方式函数未改变传入的对象的值,但可以返回另外一个对象的指针。注意返回的指针必须指向全局的对象,如果返回函数内定义的对象,退出函数作用域后,其指针将无效,这是非常危险的;如果Dealwith是成员函数,也可以返回指向成员的指针。
2.在类中的使用,返回一个类的成员,但不希望调用方修改这个成员。
方式<1>
class MyData
{
public :
MyData(std::string name, Data data)
{
m_name = name;
m_data = data;
}
const Data* GetData()
{
return &m_data;
}
private:
std::string m_name;
Data m_data;
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
调用如下:
MyData mydata("", Data(100));
const Data* pData = mydata.GetData();
cout << pData->value << endl;
方式<2>
有人可能会问GetData也可以写成这样:
const Data& GetData()
{
return m_data;
}
这样的话,调用方常常容易写成这样:
MyData mydata("", Data(100));
Data data = mydata.GetData(); //这会有个赋值的过程,会把mydata.m_data赋给data
cout << data.value << endl; //data.value = 100
data.value = 50; //正确,data.value=50,但mydata.m_data.value还是100
这样调用时会有一个结果赋值的过程,如果Data是一个复杂的类,会有较大的开销,其效果与下面这种方式是一样的:
Data GetData()
{
return m_data;
}
当然,如果调用方这样使用是正确的:
const Data& GetData()
{
return m_data;
}
MyData mydata("", Data(100));
const Data& data = mydata.GetData(); //这会有个赋值的过程,会把mydata.m_data赋给data
cout << data.value << endl; //data.value = 100
//data.value = 50; //错误,data是一个对常量的引用,不能改变其邦定的对象
这对调用方的技术能力要求比较高,如果你是设计方,一定要尽量使接口简单易用。
方式<3>
如果你要传入一个Data进行一些处理,处理完后返回类的成员m_data,可如下实现:
void DoSomething(const Data*& pData)
{
if (pData != NULL)
{
}
pData = &m_data;
}