设为首页 加入收藏

TOP

C/C++语言中关于const用法的总结(一)
2015-11-10 13:45:32 来源: 作者: 【 】 浏览:7
Tags:C/C 言中 关于 const 用法 总结

一. const的基本功能与用法


1.将限定符声明为只读


使用方法如下,在类型前/后加上关键字const,该变量必须被初始化,否则编译错误;该变量不能被重新赋值,否则也编译错误。
举例:


const int i = 50;? // 编译正确
const int j;? ? ? ? // 编译错误
int k = 0;
i = k;? ? ? ? ? ? ? // 编译错误
k = i;? ? ? ? ? ? ? // 编译正确1
2.用于修饰函数形参,保护参数使其不被修改


用法1:若形参为const A* a,则不能改变函数所传递的指针内容,这样对指针所指向的内容起到保护作用,这里需要注意的是,该修饰不能改变指针所指向地址所存储的内容,但是指针a所指向的地址可以被改变,具体例子如下:


void Test(const int *a)
{
? ? *a = 1;? ? ? ? ? //错误,*a不能被赋值
? ? a = new int(10086);? //正确,为指针a开辟新的空间,并令*a=2
}


int main()
{
? ? int *a = new int(10000);
? ? Test(a);
? ? return 0;
}1
用法2:若形参为const A& a,则不能改变函数传递进来的引用对象,从而保护了原对象的属性。


对于自定义的数据类型,用引用传递速度较快,如果不想改变原值,就可以用const来保护参数,如以下例子:


void Test(const int &a) //保护L7中的a不会被改变
{
? ? a = 2;//错误,a不能给常量赋值
}


int main()
{
? ? int a = 3;
? ? Test(a);
? ? return 0;
}事实上对于内置型数据类型(如以上例子中的int类型),用引用传递不会使速度更快。如果是用引用传参,一般是为了改变参数值;如果不想改变参数的值,直接值传递即可,不必使用const修饰。而对于自定义数据类型的输入参数,为了提高速度和效率,应使用“const + 引用传递”代替值传递。例如:


将函数 void Test(A a) 改为-> void Test(const A &a)


3.用于修饰函数返回值


用法1:用const修饰返回值为对象本身(非引用和指针)的情况多用于二目操作符重载函数并产生新对象的时候
举例:


const Rational operator*(const Rational& lhs, const Rational& rhs)
{
? ? return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}
Rational a,b;
Radional c;
(a*b) = c;//错误1
用法2:不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。原因如下:如果返回值为某个对象为const(const A test = A 实例)或某个对象的引用为const(const A& test = A实例) ,则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到,具体例子如下:


class A
{
public:
? ? int y;
? ? A(int y):x(x),y(y){};
? ? void Sety(int y){this->y = y;}
};


const A Test1(A a)
{
? ? return a;
}


const A& Test2(A &a)
{
? ? return a;
}


int main()
{
? ? A a(2);
? ? Test1(a).Sety(3);//错误,因为Test1(a)的返回值是个const,不能被Sety(3)修改
? ? Test2(a).Sety(3);//错误,因为Test1(a)的返回值是个const,不能被Sety(3)修改
? ? return 0;
}用法3:如果给采用“指针传递”方式的函数返回值加const修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。例子如下:


const char * GetString(void){}
int main()
{
? ? char *str1=GetString();//错误
? ? const char *str2=GetString();//正确
? ? return 0;
}用法4:函数返回值采用“引用传递”的场合不多,这种方式一般只出现在类的赋值函数中,目的是为了实现链式表达。例子如下:


class A
{
? ? // 以下赋值函数的返回值加const修饰,该返回值的内容不允许修改
? ? A &operate = (const A &other);
}
A a, b, c;? // a,b,c为A的对象
a = b = c;? ? ? // 正确
(a = b) = c;? ? // 错误,a = b的返回值不允许被再赋值1
4.在类成员函数的函数体后加关键字const


在类成员函数的函数体后加关键字const,形如:void fun() const; 在函数过程中不会修改数据成员。如果在编写const成员函数时,不慎修改了数据成员,或者调用了其他非const成员函数,编译器将报错,这大大提高了程序的健壮性。


如果不是在类的成员函数,没有任何效果,void fun() const;和void func();是一样的。


5.在另一连接文件文件中引用常量


方法:在类型前添加关键字extern const,表示引用的是常量,因此该常量不允许被再次赋值,举例如下:


extern const int i;? ? ? // 正确
extern const int j = 10;? // 错误,常量不可以被再次赋值二.const常量与#define的区别


1.const常量有数据类型,而宏常量没有数据类型


宏常量只进行简单的字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误,如:


#define I = 10
const long &i = 10;
// 由于编译器的优化,使得在const long i=10时i不被分配内存
// 而是已10直接代入以后的引用中,以致在以后的代码中没有错误
//一旦你关闭所有优化措施,即使const long i = 10也会引起后面的编译错误。
char h = I; // 正确
char h = i; // 编译警告,可能由于数的截短带来错误赋值2.使用const可以避免不必要的内存分配


从汇编的角度来看,const定义常量只是给出了对应的内存地址, 而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。例子如下:


#define k "Hello world!"
const char pk[]="Hello world!";
printf(k);? ? ? // 为k分配了第一次内存
printf(pk);? ? // 为pk一次分配了内存,以后不再分配
printf(k);? ? ? // 为k分配了第二次内存
printf(pk);三. 使用const的一些注意事项


1.修改const 所修饰的常量值


以下例子中,i为const修饰的变量,可以通过对i进行类型强制转换,将地址赋给一个新的变量,对该新的变量再作修改即可以改变原来const 修饰的常值。


const int i=0;
int *p=(int*)&i;
p=100;2.构造函数不能被声明为const


3.const数据成员的初始化只能在类的构造函数的初始化表中进行


class A
{
public:
? ? const int a;
? ? A(int x):a(x)//正确
? ? {
? ? ? ? a = x;/

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Java transient关键字使用小记 下一篇ARM汇编指令调试方法

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: