在哪里可以做公司网站,主机屋网站在那注册,wordpress情侣博客,厦门网站建设找维品From: http://blog.csdn.net/wuliming_sc/article/details/3717017 const修饰普通变量和指针
const修饰变量#xff0c;一般有两种写法#xff1a;
const TYPE value;
TYPE const value;
这两种写法在本质上是一样的。它的含义是#xff1a;const修饰的类型为TYPE的变…From: http://blog.csdn.net/wuliming_sc/article/details/3717017 const修饰普通变量和指针
const修饰变量一般有两种写法
const TYPE value;
TYPE const value;
这两种写法在本质上是一样的。它的含义是const修饰的类型为TYPE的变量value是不可变的。对于一个非指针的类型TYPE无论怎么写都是一个含义即value值不可变。例如
const int nValue //nValue是const
int const nValue //nValue是const
但是对于指针类型的TYPE不同的写法会有不同情况
l 指针本身是常量不可变
(char*) const pContent;
l 指针所指向的内容是常量不可变
const (char) *pContent;
(char) const *pContent;
l 两者都不可变
const char* const pContent;
识别const到底是修饰指针还是指针所指的对象还有一个较为简便的方法也就是沿着*号划一条线
如果const位于*的左侧则const就是用来修饰指针所指向的变量即指针指向为常量
如果const位于*的右侧const就是修饰指针本身即指针本身是常量。
const修饰函数参数
const修饰函数参数是它最广泛的一种用途它表示在函数体中不能修改参数的值(包括参数本身的值或者参数其中包含的值)
void function(const int Var); //传递过来的参数在函数内不可以改变(无意义该函数以传值的方式调用)
void function(const char* Var); //参数指针所指内容为常量不可变
void function(char* const Var); //参数指针本身为常量不可变(也无意义var本身也是通过传值的形式赋值的)
void function(const Class Var); //引用参数在函数内不可以改变
参数const通常用于参数为指针或引用的情况若输入参数采用“值传递”方式由于函数将自动产生临时变量用于复制该参数该参数本就不需要保护所以不用const修饰。
const修饰类对象/对象指针/对象引用
const修饰类对象表示该对象为常量对象其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。
const修饰的对象该对象的任何非const成员函数都不能被调用因为任何非const成员函数会有修改成员变量的企图。
例如
class AAA
{ void func1();
void func2() const;
}
const AAA aObj;
aObj.func1(); 错误
aObj.func2(); 正确 const AAA* aObj new AAA();
aObj-func1(); 错误
aObj-func2(); 正确
const修饰数据成员
const数据成员只在某个对象生存期内是常量而对于整个类而言却是可变的。因为类可以创建多个对象不同的对象其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员因为类的对象未被创建时编译器不知道const 数据成员的值是什么例如 class A { const int size 100; //错误 int array[size]; //错误未知的size } const数据成员的初始化只能在类的构造函数的初始化列表中进行。要想建立在整个类中都恒定的常量可以用类中的枚举常量来实现例如 class A {
… enum {size1100, size2 200 }; int array1[size1]; int array2[size2];
… } 枚举常量不会占用对象的存储空间他们在编译时被全部求值。但是枚举常量的隐含数据类型是整数其最大值有限且不能表示浮点数。
const修饰成员函数
const修饰类的成员函数用const修饰的成员函数不能改变对象的成员变量。一般把const写在成员函数的最后
class A
{ …
void function()const; //常成员函数, 它不改变对象的成员变量. 也不能调用类中任何非const成员函数。
}
对于const类对象/指针/引用只能调用类的const成员函数。
修饰成员函数的返回值
、一般情况下函数的返回值为某个对象时如果将其声明为const时多用于操作符的重载。通常不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。原因如下如果返回const对象或返回const对象的引用则返回值具有const属性返回实例只能访问类A中的公有保护数据成员和const成员函数并且不允许对其进行赋值操作这在一般情况下很少用到。 2、如果给采用“指针传递”方式的函数返回值加const修饰那么函数返回值即指针所指的内容不能被修改该返回值只能被赋给加const 修饰的同类型指针 const char * GetString(void); 如下语句将出现编译错误 char *strGetString(); 正确的用法是 const char *strGetString(); 3、函数返回值采用“引用传递”的场合不多这种方式一般只出现在类的赙值函数中目的是为了实现链式表达。如 class A {
… A operate (const A other); //赋值函数 } A a,b,c; //a,b,c为A的对象 … abc; //正常 (aB)c; //不正常但是合法 若赋值函数的返回值加const修饰那么该返回值的内容不允许修改上例中abc依然正确。(ab)c就不正确了。
const常量与define宏定义的区别
l 编译器处理方式不同
define宏是在预处理阶段展开。
const常量是编译运行阶段使用。
l 类型和安全检查不同
define宏没有类型不做任何类型检查仅仅是展开。
const常量有具体的类型在编译阶段会执行类型检查。
l 存储方式不同
define宏仅仅是展开有多少地方使用就展开多少次不会分配内存。
const常量会在内存中分配(可以是堆中也可以是栈中)。
volatile关键字
volatile的本意是“易变的”,volatile关键字是一种类型修饰符用它声明的类型变量表示可以被某些编译器未知的因素更改比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量编译器对访问该变量的代码就不再进行优化从而可以提供对特殊地址的稳定访问。
当要求使用volatile 声明的变量的值的时候系统总是重新从它所在的内存读取数据即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被寄存。例如 volatile int i10; int a i; 。。。//其他代码并未明确告诉编译器对i进行过操作 int b i; volatile 指出 i是随时可能发生变化的每次使用它的时候必须从i的地址中读取因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来如果i是一个寄存器变量或者表示一个端口数据就容易出错所以说volatile可以保证对特殊地址的稳定访问。 注意在vc6中一般调试模式没有进行代码优化所以这个关键字的作用看不出来。下面通过插入汇编代码测试有无volatile关键字对程序最终代码的影响。首先用classwizard建一个win32 console工程插入一个voltest.cpp文件输入下面的代码 #include stdio.h void main() { int i10; int a i; printf(i %d/n,a); //下面汇编语句的作用就是改变内存中i的值但是又不让编译器知道 __asm { mov dword ptr [ebp-4], 20h } int b i; printf(i %d/n,b); } 然后在调试版本模式运行程序输出结果如下
i 10
i 32
然后在release版本模式运行程序输出结果如下
i 10
i 10 输出的结果明显表明release模式下编译器对代码进行了优化第二次没有输出正确的i值。下面我们把 i的声明加上volatile关键字看看有什么变化 #include stdio.h void main() { volatile int i10; int a i; printf(i %d/n,a); __asm { mov dword ptr [ebp-4], 20h } int b i; printf(i %d/n,b); } 分别在调试版本和release版本运行程序输出都是
i 10
i 32
这说明这个关键字发挥了它的作用 关于volatile的补充信息
一个定义为volatile的变量是说这变量可能会被意想不到地改变这样编译器就不会去假设这个变量的值了。精确地说就是优化器在用到这个变量时必须每次都小心地重新读取这个变量的值而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子 1). 并行设备的硬件寄存器如状态寄存器 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3). 多线程应用中被几个任务共享的变量 我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。假设被面试者正确地回答了这是问题嗯怀疑这否会是这样我将稍微深究一下看一下这家伙是不是直正懂得volatile的重要性 1). 一个参数既可以是const还可以是volatile吗解释为什么。 2). 一个指针可以是volatile 吗解释为什么。 3). 下面的函数有什么错误 int square(volatile int *ptr) { return *ptr * *ptr; } 下面是答案 1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。 2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。 3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方但是由于*ptr指向一个volatile型参数编译器将产生类似下面的代码 int square(volatile int *ptr) { int a,b; a *ptr; b *ptr; return a * b; } 由于*ptr的值可能被意想不到地该变因此a和b可能是不同的。结果这段代码可能返不是你所期望的平方值正确的代码如下 long square(volatile int *ptr) { int a; a *ptr; return a * a; } mutable关键字
mutalbe的中文意思是“可变的易变的”跟constant既C中的const是反义词。在C中mutable也是为了突破const的限制而设置的。被mutable修饰的变量(mutable只能由于修饰类的非静态数据成员)将永远处于可变的状态即使在一个const函数中。
我们知道假如类的成员函数不会改变对象的状态那么这个成员函数一般会声明为const。但是有些时候我们需要在const的函数里面修改一些跟类状态无关的数据成员那么这个数据成员就应该被mutalbe来修饰。下面是一个小例子 class ClxTest { public: void Output() const; }; void ClxTest::Output() const { cout Output for test! endl; } void OutputTest(const ClxTest lx) { lx.Output(); } 类ClxTest的成员函数Output是用来输出的不会修改类的状态所以被声明为const。
函数OutputTest也是用来输出的里面调用了对象lx的Output输出方法为了防止在函数中调用成员函数修改任何成员变量所以参数也被const修饰。
假如现在我们要增添一个功能计算每个对象的输出次数。假如用来计数的变量是普通的变量的话那么在const成员函数Output里面是不能修改该变量的值的而该变量跟对象的状态无关所以应该为了修改该变量而去掉Output的const属性。这个时候就该我们的mutable出场了只要用mutalbe来修饰这个变量所有问题就迎刃而解了。下面是修改过的代码 class ClxTest { public: ClxTest(); ~ClxTest(); void Output() const; int GetOutputTimes() const; private: mutable int m_iTimes; }; ClxTest::ClxTest() { m_iTimes 0; } ClxTest::~ClxTest() {} void ClxTest::Output() const { cout Output for test! endl; m_iTimes; } int ClxTest::GetOutputTimes() const { return m_iTimes; } void OutputTest(const ClxTest lx) { cout lx.GetOutputTimes() endl; lx.Output(); cout lx.GetOutputTimes() endl; } 计数器m_iTimes被mutable修饰那么它就可以突破const的限制在被const修饰的函数里面也能被修改。 参考资料 http://www.cppblog.com/jukevin/archive/2008/12/27/70499.html http://dev.csdn.net/develop/article/50/50538.shtm http://www.eb163.com/club/thread-956-1-1.html http://www.diybl.com/course/3_program/c/cppjs/200798/70290_4.html