C++的const声明:原因和使用

栏目: C++ · 发布时间: 5年前

内容简介:概念上它是直观的:最简单的使用方式是声明一个命名常量。这在C++/C及衍生语言中都可用。

const 关键字是C++众多杂乱特性中的一个。

概念上它是直观的: const 修饰的变量变成常量,程序不能修改其值。然而它是C++缺失特性的一个简单粗暴的解决办法,并因此导致它变得非常复杂,在使用上有时还有让人不爽的限制。接下来的部分将尝试解释 const 如何使用(How)及其存在的原因(Why)。

const 的简单使用

最简单的使用方式是声明一个命名常量。这在C++/C及衍生语言中都可用。

具体方式是像声明变量一样声明一个常量,只是在前面加上 const 。你必须马上对它进行初始化,因为以后不能更改。例如:

const int Constant1=96;

这会创建一个整数常量 Constant1 ,并赋值96。

对编译后值不应该更改的参数,这样的常数是很有用的。相对于 C语言 的预处理宏 #define ,其在源码送到编译器前只做简单的文本替换, const 的优势在于能被编译器理解和运用,如此以来错误信息将对开发人员更有帮助。

const 也能用在指针上,但必须谨慎选择 const 的位置,因为这决定了指针还是其所指的值是常量。例如:

const int * Constant2

声明了 Constant2 是一个指针变量,其指向一个整数常量。

int const * Constant2

是另一种等价的声明方式。而

int * const Constant3

声明 Constant3 是一个指向整数的常量指针。此外

int const * const Constant4

声明 Constant4 是指向一个整数常量的常量指针。原则上说, const 的修饰范围是紧邻的左侧(如果左侧无内容则修饰右侧)( 译注: 这请结合声明的“ 顺时针螺旋法则 ”理解这句话)。

const 用在函数返回值

指针和 const 可能的组合中,在值可变但地址不变的情形下常量指针很有用。

更有用的是指向 const 值的指针(指针可以是常量,也可以不是)。函数返回常量字符串和数组时这很有用,因为它们本来就是用指针实现的,如果没有 const ,程序修改时将崩溃。有了 const ,编译时会检测到修改不可变常量的行为并阻止,避免程序运行时崩溃及难以定位的情况。

例如,一个返回 Some text 字符串的函数定义如下:

char *Function1()
{ return “Some text”;}

如果程序突然尝试修改其值,那么就会崩溃:

Function1()[1]=’a’;

函数改写成如下,那么编译器将抛出错误:

const char *Function1()
{ return "Some text";}

因为编译器知道函数返回值是不可变的。(当然,C++编译器理论上会推算出,但C编译器就没那么聪明了。)

混乱点 – 参数传递

当一个子例程或者函数被调用,传入数据的参数变量被读取,传出数据的参数变量被写入,或者既读取也写入。部分编程语言允许开发人员指定传入还是传出,例如使用 in: , out:inout: 提示参数类型,然而在C中,开发人员更偏底层,从而要指定参数的传递方式以及数据流动方向。 例如,一个这样的子例程:

void Subroutine1(int Parameter1)
{ printf("%d",Parameter1);}

其以值传递方式接收参数,这是C和C++的默认方式。所以子例程能读取传递过来的参数值,但是无法修改,因为对形参的修改在子例程结束后就丢弃了。例如:

void Subroutine2(int Parameter1)
{ Parameter1=96;}

调用这个函数不会让实参修改成96。 C++中加一个 & (这个符号的选择很具有迷惑性,因为C中 & 放在变量前会变成指针!)在参数前,这回让实参本身用在子例程里,所以它的值可以被更改并且能把数据从子例程中带回来。因此

void Subroutine3(int &Parameter1) 
{ Parameter1=96;}

会把实参的值修改成96。这种将变量本身传递的方式在C++中叫做“引用传递”。

这种传递变量本身的方式是C++对C的补充。原本的C语言中,要传递一个可修改的变量,要用另一种函数调用方式。这种方式用“指针”作为参数,然后修改其所指向的值。例如:

void Subroutine4(int *Parameter1) 
{ *Parameter1=96;}

能达到目的,但要求函数内的所有参数修改都这样做,并且调用函数时要传递指针。这是非常麻烦的。

const 怎么就混入这里了?好吧,有一种不使用副本,而是按引用传递数据或者用指针的常见情形。那就是拷贝副本会浪费空间或者耗时太久。尤其是大的或者复杂的用户自定义数据类型(C中的结构体以及C++中的类)。一个声明如下的子例程

void Subroutine4(big_structure_type &Parameter1);

使用 & 可能是因为函数会修改变量的值,也许只是为了节省拷贝时间。当函数编译在其他人的库时,根本没办法知道是哪种。确信子例程不会修改函数的值,这个假定回带来风险。 为了解决这个问题, const 可用在参数列表里。例如:

oid Subroutine4(big_structure_type const &Parameter1);

这让变量按引用传递避免了拷贝,同时防止它在函数内被修改。这个做法有点让人觉得混乱:就因为要让编译器做一些优化,把一个可双向修改的参数就变为只读的传入参数。

理想的情形,开发人员不应该控制参数传递的细节,而应该只指定数据方向,剩下的让编译器自动优化。但由于C被设计成一门可运行在低端计算机上的低级编程语言,开发人员不得不显式指定参数传递细节。

依然更混乱 – 用在OOP中

面向对象编程 里,调用一个对象的“方法”(面向对象对函数的称呼)回带来额外的复杂度。和参数列表中的变量一样,类方法可以直接访问对象的成员变量。例如一个普通类 Class1 定义为:

class Class1
{ void Method1();
  int MemberVariable1;}

Method1 方法没有显式参数,但是调用这个方法可能会修改 MemberVariable1 ,如果 Method1 碰巧这么做的话,例如:

void Class1::Method1()
{ MemberVariable1=MemberVariable1+1;}

解决方案是在参数列表后放一个 const ,像这样

class Class2
{ void Method1() const;
  int MemberVariable1;}

这会禁止 Class2 中的 Method1 做任何尝试修改其对象的成员变量行为。

如果有时需要结合 const 的不同用法,这可能会带来困惑:

const int*const Method3(const int*const&)const;

这里的5个 const 用法分别表示:函数返回的指针内容不能被修改,返回的指针不能被修改,方法不会修改参数数据,也不会修改参数指针,以及这是一个不会修改对象内容的方法!

const 的不便处

除了困扰人的 const 语法,还有阻止程序干活的问题。

我的程序常常要为运行速度优化,让我我特别恼火的一个点是,一个声明为 const 的方法不能修改对象的隐藏属性,而修改这些属性在外界看来并没有导致对象发生改变。这包括为后续调用省时而存储耗时计算的临时结果。因为 const ,要么把临时结果返回给调用方存储然后下次传回来(混乱),或者下次从头再算(低效)。后来版本的C++增加了 mutable 关键字解决这个问题,但是它完全依赖于开发人员只用在这个目的。所以如果你的程序用了其他人包含 mutable 的类,你不能保证 mutable 真正让对象为常量,而这会导致 const 没有实际作用。

然后你又不能简单的避免在类方法中使用 const ,因为 const 具有传染性。例如一个 const 对象,以 const & 方式作为参数传递,那么只能调用显式声明为 const 的方法(因为C++的调用系统太简单,不能推算出不显式声明为 const 但实际不改动数据的方法)。因此不改变对象的类方法最好声明为 const ,以便它们在声明为 const 的情形下可以调用。后来版本的C++,声明为 const 的变量或对象可以使用 const_cast 转成可变,这和 mutable 的手法一样简单粗暴,也会让 const 没有实际作用。


以上所述就是小编给大家介绍的《C++的const声明:原因和使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法设计技巧与分析

算法设计技巧与分析

阿苏外耶 / 电子工业出版社 / 2003-01-01 / 40.0

本书由World Scienti一起来看看 《算法设计技巧与分析》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器