const

来源:互联网 发布:linux如何安装jmeter 编辑:程序博客网 时间:2024/06/01 21:51

          关键字const 多才多艺。你可以用它在classes 外部修饰global 或namespace作用域中的常量,或修饰文件、函数、或区块作用域(block scope) 中被声明为static 的对象。你也可以用它修饰classes 内部的static 和non-static 成员变量。面对指针,你也可以指出指针自身、指针所指物,或两者都(或都不〉是const:

char greeting[ ]="Hello";

char *p=greeting; //non-const pointer,non-const data

const char *p=greeting;  //non_const pointer,const data        也有人这么用char const *p;

char * const p=greeting;  //const pointer, non-const data

const char * const p=greeting;  //const pointer, const data 

       const 语法虽然变化多端,但并不莫测高深。如果关键字const 出现在星号左边,表示被指物是常量:如果出现在星号右边,表示指针自身是常量:如果出现在星号两边,表示被指物和指针两者都是常量。

一、class专属常量

     为了将常量的作用域(scope)限制于class内,你必须让它成为class 的一个成员(member) ;而为确保此常量至多只有一份实体,你必须让它成为一个static 成员:
class GamePlayer {
private:
static const int NumTurns = 5;   //常量声明式,注意只是对整数类型可以再声明时设初值
int scores[NumTurns];               //使用该常量

....

}

       然而你所看到的是NumTurns 的声明式而非定义式。通常C++ 要求你对你所使用的任何东西提供一个定义式,但如果它是个class 专属常量又是static 且为整数类型(integral type,例如ints, chars, bools) ,则需特殊处理。只要不取它们的地址,你可以声明并使用它们而无须提供定义式。如果你取某个class 专属常量的地址,或纵使你不取其地址而你的编译器却(不正确地)坚持要看到一个定义式,你就必须另外提供定义式如下:

const int GamePlayer::NumTurns;         //NumTurns的定义,这个式子在一个实现文件而非头文。

                                                               //由于class 常量已在声明时获得初值(例如先前声明NumTurns时为它设初值5 ,因此定义时不可以再设初值。

       万一你的编译器(错误地)不允许"static 整数型class 常量"完成"in class 初值设定",可改用所谓的"the enum hack" 补偿做法。其理论基础是: "一个属于枚举类型(enumerated type) 的数值可权充ints 被使用",于是GamePlayer 可定义如下:
class GamePlayer {
private:
enum { NumTurns = 5 };     //"the enum hack" ----令NumTurns成为5 的一个记号名称
int scores[NumTurns];        //这就没问题了
....

}
        注: enum hack 的行为某方面说比较像#define 而不像const,有时候这正是你想要的。例如取一个const 的地址是合法的,但取一个enum 的地址就不合法,而取一个#define 的地址通常也不合法。

       旧式编译器不允许static 成员在其声明式上获得初值。此外所谓的" in-class 初值设定"也只允许对整数常量进行。如果你的编译器不支持上述语法,你可以将初值放在定义式:

class CostEstimate {
private:
static const double FudgeFactor;   //static class 常量声明位于头文件内
}

const double  CostEstimate:: FudgeFactor = 1.35;  //static class 常量定义位于实现文件内

二、const函数声明

       一个函数声明式内, const可以和函数返回值、各参数、函数自身(如果是成员函数)产生关联。

       令函数返回一个常量值,往往可以降低因客户错误而造成的意外,而又不至于放弃安全性和高效性。将回传值声明为const 可以预防"没意思的赋值动作"。

      除非你有需要改动参数或local 对象,否则请将它们声明为const 。只不过多打6 个字符,却可以省下恼人的错误,像是"想要键入'=='却意外键成'=' "的错误。


三、const 成员函数

      将const 实施于成员函数的目的,是为了确认该成员函数可作用于const 对象身上。

       这一类成员函数之所以重要,基于两个理由。第一,它们使class 接口比较容易被理解。这是因为,得知哪个函数可以改动对象内容而哪个函数不行,很是重要。第二,它们使"操作const 对象"成为可能。

 class TextBlock

{
public:
const char& operator[ ] (std::size_t position)  const       //perator[ ] for const 对象
                  { return text[position]; )
char& operator[ ] (std::size_t position)                           //operator [ ] for non-const 对象,注意返回类型及下面的使用

                  { return text[position]; )
private:
std::string text                                                       //注意,两个成员函数如果只是常量性(constness )不同,可以被重载。这是一个重要的
C++ 特性

};

TextBlock 的operator[ ]s 可被这么使用:

TextBlock tb ("Hello") ;
std::cout<< tb[0];                    //调用non-const TextBlock::operator[]
const TextBlock ctb("World");
std::cout <<ctb[0];                 //调用const TextBlock::operator[]

只要重载operator门并对不同的版本给予不同的返回类型,就可以令const和non-const TextBlocks获得不同的处理:
std::cout<< tb[0];        //没问题,读一个non-const TextBlock
tb[0] = 'x';                     //没问题,写一个non-const TextBlock
std::cout<< ctb[0];       //没问题,读一个const TextBlock
ctb[0] = 'x';                   //
错误!,写一个const TextBlock

请注意, non-const operator[] 的返回类型是个reference to char,不是char。如果operator[] 只是返回一个char,下面这样的句子就无法通过编译:tb[0] = 'x';因为,如果函数的返回类型是个内置类型,那么改动函数返回值从来就不合法。

真实程序中const对象大多用于passedby pointer-to-const 或passedby reference-to-const 的传递结果。上述的ctb 例子太过造作,下面这个比较真实:

void print(const TextBlock& ctb)   //此函数中ctb 是const

{std::cout <<ctb[0];                            //调用const TextBlock: : operator []

}

五、STL 选代器const

         STL 选代器系以指针为根据塑模出来,所以迭代器的作用就像个T*指针。声明选代器为const 就像声明指针为const 一样(即声明一个T* const 指针) ,表示这个迭代器不得指向不同的东西,但它所指的东西的值是可以改动的。如果你希望迭代器所指的东西不可被改动(即希望STL 模拟一个const T* 指针) ,你需要的是const_iterator:
std::vector<int> vec;
const std::vector<int>::iterator iter =vec.begin( );    //iter 的作用像个T* const
*iter = 10;                                                                   //没问题,改变iter 所指物 
++iter;                                                                           //错误! iter 是const
std: :vector<int>::const_iterator clter =vec.begin( );//clter 的作用像个const T*
*clter = 10;                                                                   //错误! *clter 是const
++clter;                                                                       // 没问题,改变clter

原创粉丝点击