linux c const 作用,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

4.在参数中使用const应该使用引用或指针,而不是一般的对象实例

合理利用const在成员函数中的三种用法(参数、返回值、函数),一般来说,不要轻易的将函数的返回值类型定为const;另外,除了重载操作符外一般不要将返回值类型定为对某个对象的const引用。

5.对于使用const修饰来指针的情况

对于以下情况,const放在变量声明符的前后位置效果是一样的,这种情况下不允许对指针a 的内容进行更改操作:

int i;

const int *a = &i;

int const*a = &i;1

但是,如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即该指针指向一个地址,该地址的内容不可变;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量:

int i;

// 以下一行表示a是一个指针,可以任意指向int常量或者int变量

// 它总是把它所指向的目标当作一个int常量

// 也可以写成int const* a

const int *a = &i;

// 以下一行表示a是一个指针常量,

// 初始化的时候必须固定指向一个int变量

// 之后就不能再指向别的地方了

// 但是指针指向的内容可以改变

int *const a = &i;6.指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如以下例子中a++是错误的:

int *const a = &i;

a++;  // 错误,a指针本身是常量,不能再指向别的地方7.当指针本身和指针所指向的内容均为常量时

这种情况下可写为:

const int * const a = &i;8.const成员函数返回的引用,也是const

#include

using namespace std;

class A

{

public:

int x;

void set(int x){this->x = x;}

// const成员函数返回的引用也是const,a

// 如果把A&前面的const去掉会出错

// 因为返回的是一个const的对象,返回类型却不是const

// 返回的内容和返回的类型不符

const A& Test1()const

{

// 错误。这是const成员函数的特点

x = 2;

// 不限于*this。不管返回的是什么,哪怕是一个定义为非const的对象,结果也是一样的

return *this;

}

};

int main()

{

A a, b;

// 正确,虽然返回的是一个const,却用另一个非const来接收

b = a.Test1();

// 错误,既然是别名,那么别名的类型要与原来的类型相同

A &c = a.Test1();

// 正确虽然在a.Test1()中a不能改变,但是这里已经出了这个成员函数的作用域

a.set(2);

// 正确,b接收了a.Test1()返回的数据的内容,但是它不是const

b.set(2);

// 错误。a.Test1()是一个对象,这个对象是它的返回值

// 虽然没有名字,但是它就是a.Test1()的返回值

// 值是a.Test1()返回的值,类型是a.Test1()返回的类型

a.Test1().set(2);

return 0;

}9.mutable将数据声明为可变数据成员

在C++语言中,mutable是使用较少的关键字,它的作用是:如果一个函数被const 修饰,那么它将无法修改其成员变量的,但是如果一个成员变量是被mutable修饰的话,则可以修改。

mutable 可以用来指出,即��成员函数或者类变量为const,其某个成员也可以被修改。反过来说,可变数据成员永远不能成为const,即使它是const对象的成员。

class A

{

public:

int x;

mutable int y;

A(int a, int b):x(a),y(b){}

};

int main()

{

const A a(0, 0); // const对象必须初始化

a.x = 1;        // 错误

a.y = 2;        // 正确,mutable修饰使得成员可被修改,即使对象a为const

return 0

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值