标签:
1. 代替#define。
讲到用const来代替#define,为什么要这样做呢,当然是const比#define更好啦,一个很明显区别就是const有数据类型,可以进行类型安全检查,而#define只是简单的替换,并这个功能。所以我们就尽量使用
const double pi = 3.1415926;
来代替这样的语句:
#define pi 3.1415926;//最好用const来定义
而且#define的定义在进入编译器前会被替换掉,这样,当涉及到这个常量的编译错误时,报告是不是pi而是3.1415926这个常量,这样就带来的调试上的麻烦。
用cosnt来代替#define还有一个好处就是减少不必要的内存分配,例如:
#define PI 3.1415926 //常量宏
const doulbe Pi=3.1415926; //此时并未将Pi放入ROM中
......
double i=Pi; //此时为Pi分配内存,以后不再分配!
double I=PI; //编译期间进行宏替换,分配内存
double j=Pi; //没有内存分配
double J=PI; //再进行宏替换,又一次分配内存!
const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝换,又一次分配内存!
2. 使某个对象(变量)、值,指针,引用不能被修改。
这一点是大家最常见,用它来定义常量,使之具有不可变性。
对于用来修饰对象(变量),非常好理解,也是经常使用const的作用之一。但对于指针,可能就不好那好理解了,具体可以看以下代码:
const int p // 相当于常量p
int const p // 同上
const int *a // 意味着a是一个指向常整型数的指针(不能通过*p来改变指向的变量的值,但是改变指针的指向,此最常见于函数的参数,当你只引用传递进来的指针所指向的值的时候加上const修饰符,程序中修改的编译就不通过,可以减少bug)
int * const a // 表示a是一个指向整型数的常指针(可以修改指向的变量的值,但是不能改变指针的指向)
int const * const a // 表示a是一个指向常整型数的常指针(即不可通过*p修改变量的值,也不可以改变指针的指向)
总结:可以这样来记忆,const在谁前边,即const修饰谁,谁不可变。读的时候谁在前先读谁,如第3个, 读作常量指针, 第4个,读作指针常量
3. 使类的静态对象在类内部可以初始化
当我们要在类的内部定义某个常量时,就可能用const来修饰,否则的话,就不能初始化,看看下面的代码
class print
{
private:
//不能写成static int count = 10;
static const int count = 10;
string info[count];
};
const int print::count;
当然出也可以通过类构造函数的初始化成员列表来初始化cosnt常量:
class A
{
public:
A(int i=0):count(i) {}
private:
const int count;
};
4. 修饰函数参数和返回值,提高程序健壮性
用const用修饰函数参数是一种常见的行为,见下面代码:
const bigint operator+(const bigint& bigvar1, const bigint& bigvar2)
{ return bigvar1.value+bigvar2.value; }
由于bigvar1和bigvar2 都是类类型,为了提高传值的效率,所以就用对象的引用,但是这样就有一个问题,我们不能阻止在函数内部修改bigvar1和bigvar2的值,解决办法只能用const,这就是我们在非内部数据类型的函数参数传递中常用的一种”const引用传递”,它可得到高效率,同时阻止函数内部对对象进行修改。
再看看对象前面的const(bigint前面) 它的作用是不允许下面的代码存在: (a+b) = c //a,b,c都是bigint类型
上面的代码很显然是没有意义,它对一个运算结果进行赋值,我们就应该加上const来阻止这样的代码发生。
对于类的成员函数,若不会修改数据成员,我们都应该有const来声明,若我编写这样的函数时不小心修改了类的数据成员或调用非const的成员函数,编译器就会给予相关的提示。看看下面的代码:
class myprint
{
public:
myprint():printcount(0){};
void print();
int getcount() const;
private:
myprint(const myprint&);
myprint& operator=(const myprint&);
int printcount;
};
在const成员函数中就会调用const版本的下标重载,非const版本一般用于修改值,比如cin>>x[i];
void myprint::print(){}
int myprint::getcount() const
{
++printcount; //错误,const成员函数不能修改类的数据成员
print(); //错误,const成员函数不能调用非const成员函数
return printcount;
}
用const来修饰成员函数实际上修饰的是this指针,所以静态成员函数不能声明为const,原因很简单:静态成员函数没有this指针。这里要注意const成员函数中关键字const是放在成员函数的最后面。
有时候我的确要在const成员函数中修改类的内部数据员,这时应该怎么办呢,幸运的是标准c++提供的关键字mutable来达到,只要在类数据成员前加上关键字mutable:
class myprint
{
public:
……
int getcount() const;
private:
……
mutable int printcount;
};
……
int myprint::getcount() const
{
++printcount;//正确,因为printcount有关键字mutable修饰
……
return printcount;
}
当然,还有其它方法(使用const_cast或通过指针间接来修改或通过成员函数的this指针)同样能达到修改的目的,但最好是用mutable。
5. 用const来修饰重载的类的成员函数。
有时候我们要为类提供成员函数的const重载版本,以适应不同情况的需要,例如
class Vector
{
private:
int rep[size];
public:
const int & operator[](int index) const // const 版本的下标重载
{
return rep[index];
}
int & operator[] (int index) // 非const版本的下标重载
{
return rep[index];
}
}
其实 const的作用应该不止上面说的那些,但可以说一些常用的功能都提到了。在合适使用cosnt的地方,应该尽量使,使程序变得简单,清晰.
最后,可以看看这个函数中所有const的意义:
const char* const foo(char const * const str) const
第一个const表示返回类型为const,也就是不能把此函数的返回值当作左值来使用。
第二个const表示指针的不可变性,但在这是可以省略,因为返类型已经是const。
第三个cosnt表示str的常量性,也就其内容是不能改变,可以写在其前面的char的前面。
第四个cosnt表示str的指针的常量性,也就是此指针不能指向别的地址。
第五个cosnt表示此函数的常量性(前提是类的成员函数),不能修改所在类的数据成员。
标签:
原文地址:http://www.cnblogs.com/benniuniu-gj/p/4451569.html