分享
 
 
 

const传奇

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

原文来自www.codeproject.com

作者:Rahul Singh

译者声明:有些地方按原文解释不通,译者根据自己的理解作了适当修改。如有不妥之处,请告知coolgrass@sina.com或参考原文。

简介

当我自己写程序需要用到const的时候,或者是读别人的代码碰到const的时候,我常常会停下来想一会儿。许多程序员从来不用const,理由是即使没用const他们也这么过来了。本文仅对const的用法稍作探讨,希望能够对提高软件的源代码质量有所帮助。

常变量

变量用const修饰,其值不得被改变。任何改变此变量的代码都会产生编译错误。Const加在数据类型前后均可。

例如:

void main(void)

{

const int i = 10; //i,j都用作常变量

int const j = 20;

i = 15; //错误,常变量不能改变

j = 25; //错误,常变量不能改变

}

常指针

Const跟指针一起使用的时候有两种方法。

const可用来限制指针不可变。也就是说指针指向的内存地址不可变,但可以随意改变该地址指向的内存的内容。

int main(void)

{

int i = 10;

int *const j = &i; //常指针, 指向int型变量

(*j)++; //可以改变变量的内容

j++; //错误,不能改变常指针指向的内存地址

}

const也可用来限制指针指向的内存不可变,但指针指向的内存地址可变。

int main(void)

{

int i = 20;

const int *j = &i; //指针,指向int型常量

//也可以写成int const *j = &i;

j++; //指针指向的内存地址可变

(*j)++; //错误,不能改变内存内容

}

看完上面的两个例子,是不是糊涂了?告诉你一个诀窍,在第一个例子中,const用来修饰指针j,j不可变(也就是指向int变量的常指针);第二个例子中,const用来修饰*j,*j不可变(也就是指向int常量的指针)。

这两种方式可以组合起来使用,使指针和内存内容都不可变。

int main(void)

{

int i = 10;

const int *const j = &i; //指向int常量的常指针

j++; //错误,不能改变指针指向的地址

(*j)++; //错误,不能改变常量的值

}

Const和引用

引用实际上就是变量的别名,这里有几条规则:

声明变量时必须初始化

一经初始化,引用不能在指向其它变量。

任何对引用的改变都将改变原变量。

引用和变量本身指向同一内存地址。

下面的例子演示了以上的规则:

void main(void)

{

int i = 10; //i和j是int型变量

int j = 20;

int &r = i; //r 是变量i的引用

int &s; //错误,声明引用时必须初始化

i = 15; //i 和 r 都等于15

i++; //i 和 r都等于16

r = 18; //i 和r 都等于18

printf("Address of i=%u, Address of r=%u",&i,&r); //内存地址相同

r = j; //i 和 r都等于20,但r不是j的引用

r++; //i 和 r 都等于21, j 仍等于20

}

用const修饰引用,使应用不可修改,但这并不耽误引用反映任何对变量的修改。Const加在数据类型前后均可。

例如:

void main(void)

{

int i = 10;

int j = 100;

const int &r = i;

int const &s = j;

r = 20; //错,不能改变内容

s = 50; //错,不能改变内容

i = 15; // i和r 都等于15

j = 25; // j和s 都等于25

}

Const和成员函数

声明成员函数时,末尾加const修饰,表示在成员函数内不得改变该对象的任何数据。这种模式常被用来表示对象数据只读的访问模式。例如:

class MyClass

{

char *str ="Hello, World";

MyClass()

{

//void constructor

}

~MyClass()

{

//destructor

}

char ValueAt(int pos) const //const method is an accessor method

{

if(pos >= 12)

return 0;

*str = 'M'; //错误,不得修改该对象

return str[pos]; //return the value at position pos

}

}

Const和重载

重载函数的时候也可以使用const,考虑下面的代码:

class MyClass

{

char *str ="Hello, World";

MyClass()

{

//void constructor

}

~MyClass()

{

//destructor

}

char ValueAt(int pos) const //const method is an accessor method

{

if(pos >= 12)

return 0;

return str[pos]; //return the value at position pos

}

char& ValueAt(int pos) //通过返回引用设置内存内容

{

if(pos >= 12)

return NULL;

return str[pos];

}

}

在上面的例子中,ValueAt是被重载的。Const实际上是函数参数的一部分,在第一个成员函数中它限制这个函数不能改变对象的数据,而第二个则没有。这个例子只是用来说明const可以用来重载函数,没有什么实用意义。

实际上我们需要一个新版本的GetValue。如果GetValue被用在operator=的右边,它就会充当一个变量;如果GetValue被用作一元操作符,那么返回的引用可以被修改。这种用法常用来重载操作符。String类的operator[]是个很好的例子。(这一段译得很烂,原文如下:In reality due to the beauty of references just the second definition of GetValue is actually required. If the GetValue method is used on the the right side of an = operator then it will act as an accessor, while if it is used as an l-value (left hand side value) then the returned reference will be modified and the method will be used as setter. This is frequently done when overloading operators. The [] operator in String classes is a good example.)

class MyClass

{

char *str ="Hello, World";

MyClass()

{

//void constructor

}

~MyClass()

{

//destructor

}

char& operator[](int pos) //通过返回引用可用来更改内存内容

{

if(pos >= 12)

return NULL;

return str[pos];

}

}

void main(void)

{

MyClass m;

char ch = m[0]; //ch 等于 'H'

m[0] = 'M'; //m的成员str变成:Mello, World

}

Const的担心

C/C++中,数据传递给函数的方式默认的是值传递,也就是说当参数传递给函数时会产生一个该参数的拷贝,这样该函数内任何对该参数的改变都不会扩展到此函数以外。每次调用该函数都会产生一个拷贝,效率不高,尤其是函数调用的次数很高的时候。

例如:

class MyClass

{

public:

int x;

char ValueAt(int pos) const //const method is an accessor method

{

if(pos >= 12)

return 0;

return str[pos]; //return the value at position pos

}

MyClass()

{

//void constructor

}

~MyClass()

{

//destructor

}

MyFunc(int y) //值传递

{

y = 20;

x = y; //x 和 y 都等于 20.

}

}

void main(void)

{

MyClass m;

int z = 10;

m.MyFunc(z);

printf("z=%d, MyClass.x=%d",z,m.x); //z 不变, x 等于20.

}

通过上面的例子可以看出,z没有发生变化,因为MyFunc()操作的是z的拷贝。为了提高效率,我们可以在传递参数的时候,不采用值传递的方式,而采用引用传递。这样传递给函数的是该参数的引用,而不再是该参数的拷贝。然而问题是如果在函数内部改变了参数,这种改变会扩展到函数的外部,有可能会导致错误。在参数前加const修饰保证该参数在函数内部不会被改变。

class MyClass

{

public:

int x;

MyClass()

{

//void constructor

}

~MyClass()

{

//destructor

}

int MyFunc(const int& y) //引用传递, 没有任何拷贝

{

y =20; //错误,不能修改常变量

x = y

}

}

void main(void)

{

MyClass m;

int z = 10;

m.MyFunc(z);

printf("z=%d, MyClass.x=%d",z,m.x); //z不变, x等于10.

}

如此,const通过这种简单安全机制使你写不出那种说不定是什么时候就会掉过头来咬你一口的代码。你应该尽可能的使用const引用,通过声明你的函数参数为常变量(任何可能的地方)或者定义那种const method,你就可以非常有效确立这样一种概念:本成员函数不会改变任何函数参数,或者不会改变任何该对象的数据。别的程序员在使用你提供的成员函数的时候,不会担心他们的数据被改得一塌糊涂。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有