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声明:原因和使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Distributed Algorithms

Distributed Algorithms

Wan Fokkink / The MIT Press / 2013-12-6 / USD 40.00

This book offers students and researchers a guide to distributed algorithms that emphasizes examples and exercises rather than the intricacies of mathematical models. It avoids mathematical argumentat......一起来看看 《Distributed Algorithms》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具