const char*, char const*, char*const的区别问题几乎是C++面试中每次都会有的题目。
事实上这个概念谁都有只是三种声明方式非常相似很容易记混。
Bjarne在他的The C++ Programming Language里面给出过一个助记的方法:
把一个声明从右向左读。
char * const cp; ( * 读成 pointer to )
cp is a const pointer to char
const char * p;
p is a pointer to const char;
char const * p;
同上因为C++里面没有const*的运算符,所以const只能属于前面的类型。
经常看到一些公司的笔试题中考到const,如果能在程序题中使用const,那么程序题的得分必然会高一个等级,偶现在来总结一下。
参考书目王咏刚 王咏武<<道法自然-面向对象实践指南>>
1.使用const的好处
1.1在<<C++编程规范>>中的说法是“尽量使用const来代替#define”.如果你使用下面的语句定义一个宏(宏:文字替换而已)
const int MAX_LENGTH = 100;
编译器就可以看到MAX_LENGTH这个符号,并且可以对MAX_LENGTH进行类型检查,在代码发生错误时也能正确地报出错误位置。
1.2在团队开发中有用,比如你写一个函数计算字符串的长度,原型写成int MyStrLen(const char * str),则表示这个函数并不会改变str所指向的内容(即*str).这样使用起来更加安全,该const限制能保证团队的开发人员按正确的方式使用已有代码。
2.使用const来标识常量
这个是笔试喜欢考的东东,考改错的可能性比较大,或者问答题(偶上次TrendMicro考的是改错题,偶做得还不错)
//整型常量,以后不能再对它赋值,因此必需赋一个初值
int const number = 1;
//同上,可见const放在int前面或后面的意义是一样的
const int number = 1;
//指向常量的变量指针,*p不可变,p可变(可指向别处)
int const *p;
//同上,可见const 放在int 前面或后面的意义是一样的
const int *p;
//指向变量的常量指针,p不可变,但p指向的内容number1可变,p以后不能改变,所以必须赋初值
int* const p = &number1;
//指向常量的常量指针,p不可变,number也不可变,p以后不能改变,所以必须赋初值
const int * const p = &number;
//引用,C++引用都是常量引用,引用的指向不可变,一个引用指向一个变量后就不能再改变它使它指向另一个变量(因此必
//须赋初值),当然引用所指向的内容可以改变(人家指向的是变量嘛),引用一般是出现在函数的参数中
int & number2 = number;
这个其实很容易记的,主要是看const修饰的是谁
3.修饰类的常量成员
如果一个常量只会在一个类里使用,那么我们就不应该把它定义为全局常量,我们应该把我定义在类的内部
{
const int MAX_LENGTH = 100;
class Example
public:
,要移到外面去
const int Example::MAX_LENGTH = 100;//static 的常量不能在类中定义
4.修饰函数的参数
大家都知道C++中函数的参数是按值传递的,当我们要传入一个大型对象的时候,使用按值传递就很不实惠,因为按值传递会生成该对象的一个COPY.浪费呀!!因此在传递对象的时候最好使用指针或引用.
但是在一般情况下,我们并不希望函数改变我们所传入的参数,而使用指针或引用做参数就存在被修改的可能性.
因此对于不应当被修改的东东我们应当使用const来修饰之
比如写一个字符串COPY的函数
bool CopyString(MyString& szDest,const MyString& szSrc);//假设MyString是我自己定义的一个字符串类
上面的函数表明,源字符串szSrc不会(也不应当)被CopyString函数修改,而目标字符串szDest当然要改变了.
5.修饰类的成员函数
先写一个不用const修饰成员函数的类
class MyString//我的字符串类(仅仅用于教学,没有什么实际的意义)
{
//......
private:
int GetLength();//获得串的长度 void SetLength(int len);//设置长度
//......
};
///GetLength的实现
int MyString::GetLength()
{
return this->len;
}
///SetLength的实现
void MyString::SetLength(int len)
{
this->len = len;
}
类的成员函数(内联除外)是另外安排空间的,并不放在类的里面,类的各个对象调用的都是外部的同一个函数.如:
MyString s2;
s2.SetLength(2);
s1与s2调用的是同一份函数体,那SetLength(...)如何区分来自于不同的对象的调用呢?参考<<深度探索C++对象模型>>可知道
其实GetLength函数的原型并不是GetLength( ),而是GetLength(MyString * const this),当s1调用GetLength时其实是调用GetLength(s1),这里用const来修饰this说明this是一个不可变的指针,你不能在GetLength函数里把它指向别处,当然你可以改变this所指向的内容.
使用const修饰类的成员函数(就是在括号后加上一个const,形如:int GetLength()const;),编译器会为我们生成以下函数
GetLength(MyString const * const this)
由该原型可以看出,const修饰成员函数的作用在于:表明该成员函数不会修改*this内容,比如GetLength的职责只是返回字符串的长度,而不是修改对象中的任何数据.
下面说说作用(也就是笔试考点) PS:前几天趋势公司考过,怕大家以后笔试遇到,于是就帖出来了
bool CopyString(MyString & szDest,const MyString & szStr)
{
//......
szDest.SetLength(szStr.GetLength());//假设我们就只做这件无聊的事
//......
}
如果GetLength不是const型,则不能编译通过,解释如下
CopyString的第二个参数 const MyString & szStr表明szStr是一个const引用,当szStr.GetLength()时传递给GetLength的第一个参数是szStr的类型是MyString const *const szStr,
而未经const修饰的GetLength接受的第一个参数是MyString * const this,两者不匹配编译出错
如果用const修饰GetLength则GetLength的第一个参数是MyString const * const this 与szStr匹配,编译通过