const小议.docx
《const小议.docx》由会员分享,可在线阅读,更多相关《const小议.docx(8页珍藏版)》请在冰豆网上搜索。
![const小议.docx](https://file1.bdocx.com/fileroot1/2022-12/11/1b4f67b4-2f1d-40d4-ac07-6c5dd6336c04/1b4f67b4-2f1d-40d4-ac07-6c5dd6336c041.gif)
const小议
浅谈const(精华转)
当我自己写程序需要用到const的时候,或者是读别人的代码碰到const的时候,我常常会停下来想一会儿。
许多程序员从来不用const,理由是即使没用const他们也这么过来了。
本文仅对const的用法稍作探讨,希望能够对提高软件的源代码质量有所帮助。
常变量
变量用const修饰,其值不得被改变。
任何改变此变量的代码都会产生编译错误。
Const加在数据类型前后均可。
例如:
voidmain(void)
{
constinti=10;//i,j都用作常变量
intconstj=20;
i=15;//错误,常变量不能改变
j=25;//错误,常变量不能改变
}
常指针
Const跟指针一起使用的时候有两种方法。
const可用来限制指针不可变。
也就是说指针指向的内存地址不可变,但可以随意改变该地址指向的内存的内容。
intmain(void)
{
inti=10;
int*constj=&i;//常指针,指向int型变量
(*j)++;//可以改变变量的内容
j++;//错误,不能改变常指针指向的内存地址
}
const也可用来限制指针指向的内存不可变,但指针指向的内存地址可变。
intmain(void)
{
inti=20;
constint*j=&i;//指针,指向int型常量
//也可以写成intconst*j=&i;
j++;//指针指向的内存地址可变
(*j)++;//错误,不能改变内存内容
}
看完上面的两个例子,是不是糊涂了?
告诉你一个诀窍,在第一个例子中,const用来修饰指针j,j不可变(也就是指向int变量的常指针);第二个例子中,const用来修饰*j,*j不可变(也就是指向int常量的指针)。
这两种方式可以组合起来使用,使指针和内存内容都不可变。
intmain(void)
{
inti=10;
constint*constj=&i;//指向int常量的常指针
j++;//错误,不能改变指针指向的地址
(*j)++;//错误,不能改变常量的值
}
Const和引用
引用实际上就是变量的别名,这里有几条规则:
声明变量时必须初始化
一经初始化,引用不能在指向其它变量。
任何对引用的改变都将改变原变量。
引用和变量本身指向同一内存地址。
下面的例子演示了以上的规则:
voidmain(void)
{
inti=10;//i和j是int型变量
intj=20;
int&r=i;//r是变量i的引用
int&s;//错误,声明引用时必须初始化
i=15;//i和r都等于15
i++;//i和r都等于16
r=18;//i和r都等于18
printf("Addressofi=%u,Addressofr=%u",&i,&r);//内存地址相同
r=j;//i和r都等于20,但r不是j的引用
r++;//i和r都等于21,j仍等于20
}
用const修饰引用,使应用不可修改,但这并不耽误引用反映任何对变量的修改。
Const加在数据类型前后均可。
例如:
voidmain(void)
{
inti=10;
intj=100;
constint&r=i;
intconst&s=j;
r=20;//错,不能改变内容
s=50;//错,不能改变内容
i=15;//i和r都等于15
j=25;//j和s都等于25
}
Const和成员函数
声明成员函数时,末尾加const修饰,表示在成员函数内不得改变该对象的任何数据。
这种模式常被用来表示对象数据只读的访问模式。
例如:
classMyClass
{
char*str="Hello,World";
MyClass()
{
//voidconstructor
}
~MyClass()
{
//destructor
}
charValueAt(intpos)const//constmethodisanaccessormethod
{
if(pos>=12)
return0;
*str='M';//错误,不得修改该对象
returnstr[pos];//returnthevalueatpositionpos
}
}
Const和重载
重载函数的时候也可以使用const,考虑下面的代码:
classMyClass
{
char*str="Hello,World";
MyClass()
{
//voidconstructor
}
~MyClass()
{
//destructor
}
charValueAt(intpos)const//constmethodisanaccessormethod
{
if(pos>=12)
return0;
returnstr[pos];//returnthevalueatpositionpos
}
char&ValueAt(intpos)//通过返回引用设置内存内容
{
if(pos>=12)
returnNULL;
returnstr[pos];
}
}
在上面的例子中,ValueAt是被重载的。
Const实际上是函数参数的一部分,在第一个成员函数中它限制这个函数不能改变对象的数据,而第二个则没有。
这个例子只是用来说明const可以用来重载函数,没有什么实用意义。
实际上我们需要一个新版本的GetValue。
如果GetValue被用在operator=的右边,它就会充当一个变量;如果GetValue被用作一元操作符,那么返回的引用可以被修改。
这种用法常用来重载操作符。
String类的operator[]是个很好的例子。
(这一段译得很烂,原文如下:
InrealityduetothebeautyofreferencesjusttheseconddefinitionofGetValueisactuallyrequired.IftheGetValuemethodisusedonthetherightsideofan=operatorthenitwillactasanaccessor,whileifitisusedasanl-value(lefthandsidevalue)thenthereturnedreferencewillbemodifiedandthemethodwillbeusedassetter.Thisisfrequentlydonewhenoverloadingoperators.The[]operatorinStringclassesisagoodexample.)
classMyClass
{
char*str="Hello,World";
MyClass()
{
//voidconstructor
}
~MyClass()
{
//destructor
}
char&operator[](intpos)//通过返回引用可用来更改内存内容
{
if(pos>=12)
returnNULL;
returnstr[pos];
}
}
voidmain(void)
{
MyClassm;
charch=m[0];//ch等于'H'
m[0]='M';//m的成员str变成:
Mello,World
}
Const的担心
C/C++中,数据传递给函数的方式默认的是值传递,也就是说当参数传递给函数时会产生一个该参数的拷贝,这样该函数内任何对该参数的改变都不会扩展到此函数以外。
每次调用该函数都会产生一个拷贝,效率不高,尤其是函数调用的次数很高的时候。
例如:
classMyClass
{
public:
intx;
charValueAt(intpos)const//constmethodisanaccessormethod
{
if(pos>=12)
return0;
returnstr[pos];//returnthevalueatpositionpos
}
MyClass()
{
//voidconstructor
}
~MyClass()
{
//destructor
}
MyFunc(inty)//值传递
{
y=20;
x=y;//x和y都等于20.
}
}
voidmain(void)
{
MyClassm;
intz=10;
m.MyFunc(z);
printf("z=%d,MyClass.x=%d",z,m.x);//z不变,x等于20.
}
通过上面的例子可以看出,z没有发生变化,因为MyFunc()操作的是z的拷贝。
为了提高效率,我们可以在传递参数的时候,不采用值传递的方式,而采用引用传递。
这样传递给函数的是该参数的引用,而不再是该参数的拷贝。
然而问题是如果在函数内部改变了参数,这种改变会扩展到函数的外部,有可能会导致错误。
在参数前加const修饰保证该参数在函数内部不会被改变。
classMyClass
{
public:
intx;
MyClass()
{
//voidconstructor
}
~MyClass()
{
//destructor
}
intMyFunc(constint&y)//引用传递,没有任何拷贝
{
y=20;//错误,不能修改常变量
x=y
}
}
voidmain(void)
{
MyClassm;
intz=10;
m.MyFunc(z);
printf("z=%d,MyClass.x=%d",z,m.x);//z不变,x等于10.
}
如此,const通过这种简单安全机制使你写不出那种说不定是什么时候就会掉过头来咬你一口的代码。
你应该尽可能的使用const引用,通过声明你的函数参数为常变量(任何可能的地方)或者定义那种constmethod,你就可以非常有效确立这样一种概念:
本成员函数不会改变任何函数参数,或者不会改变任何该对象的数据。
别的程序员在使用你提供的成员函数的时候,不会担心他们的数据被改得一塌糊涂。