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
- const
- const
- const
- CONST
- const
- const
- const
- const
- const
- const
- Const
- const
- const
- const
- CONST
- const
- const
- const
- VS2010“无法在证书存储区中找到清单签名证书”的解决办法
- sp短信平台软件模块清单
- How to Compile Android on Ubuntu (12.04)
- Function Prototype
- 插入排序
- const
- 在windows下开发的常见错误——持续更新,不断完善
- poj 1251(Kruskal)
- PPT排版技巧
- MongoDb在C#中查询
- lamp ubuntu
- 彩信平台软件模块清单
- 数据在磁盘上的分布
- c++静态那些事