您的位置:首页 > 其它

const用法小结

2013-08-29 13:47 120 查看



1. 定义const常量:在定义一个const常量时必须赋以初值,而且之后不能更改。

定义格式:(1) const 类型名 变量名 =常量或者常量表达式;

(2) 类型名 const 变量名 = 常量或者常量表达式;

如: const int iVal = 8;

iVal= 10;//错误,不允许更改

2. const引用:指向const对象的引用。

定义格式:(1)const <类型说明符> &<变量名> =


(2)<类型说明符> const &<变量名> =

普通引用不能绑定到const 对象,但const 引用可以绑定到非const 对象。
const int iVal = 8;

int &p = iVal; //错误

const int &p = iVal; //正确

非const 引用只能绑定到与该引用同类型的对象。
const 引用则可以绑定到不同但相关的类型的对象或绑定到右值。

(1) constint &r = 100; // 绑定到字面值常量
(2) inti = 50;
const int &r2 = r + i; // 引用r绑定到右值
(3) doubledVal = 3.1415;
const int &ri = dVal; // 整型引用绑定到double 类型
编译器会把以上代码转换成如下形式的编码:
int temp= dVal; // 创建临时变量
const int&ri = temp; // 把引用指向临时变量

3. const修饰指针:

(1) 指向const对象的指针:指针本身可以重新指向,但是所指向的内容不能修改。

定义格式:const <类型说明符> *<变量名>

<类型说明符> const *<变量名>
允许把非const 对象的地址赋给指向const
对象的指针:

int iVal;

const int*p = &iVal;

iVal = 10;

*p = 11; //错误 此时*p 是只读的,不能修改其值。

如何将一个const
对象合法地赋给一个普通指针???

例如:

const doubledVal = 3.14;

double*ptr = &dVal; // 错误

double*ptr = const_cast<double*>(&dVal);

// const_cast是C++中标准的强制转换,C语言使用:double *ptr = (double*)&dVal;

(2).const 指针:指针指向不能改变

声明或定义的格式如下(定义时必须初始化):
<类型说明符> *const <变量名> = ……
例如:
int iVal1=0;
int iVal2= 10;
int *constp = &iVal;
p = &iVa2l;//错误 指针的指向不能被修改。
*p = 1;// 正确 指针所指向的基础对象可以修改。
(3) 指向const 对象的const 指针:指针本身和指向的内容均不能改变

声明或定义的格式如下(定义时必须初始化):

const <类型说明符> *const <变量名> = ……

例如:

const doublepi = 3.14159;

const doubledVal = 3.14;

const double*const pi_ptr = π

pi_ptr= &dVal; // 错误指针的指向不能被修改。

*pi_ptr= dVal; // 错误指针所指向的基础对象也不能被修改。

4. const 修饰一般函数

(1) 修饰函数参数

void func1(const int i); // i不能被修改

void func3 (const A &rA); // rA所引用的对象不能被修改

void func2 (const char *pstr); // pstr所指向的内容不能被修改

(2) 修饰函数的返回值

返回值:const int func1(); // 此处返回int 类型的const值,意思指返回的原函数里的变量的初值不能被修改,但是函数按值返回的这个变量被制成副本,能不能被修改就没有了意义,它可以被赋给任何的const或非const类型变量,完全不需要加上这个const关键字。

[注意]但这只对于内部类型而言(因为内部类型返回的肯定是一个值,而不会返回一个变量,不会作为左值使用,否则编译器会报错),对于用户自定义类型,返回值是常量是非常重要的(后面在类里面会谈到)。

返回引用:const int &func2(); // 注意千万不要返回局部对象的引用,否则会报运行时错误:因为一旦函数结束,局部对象被释放,函数返回值指向了一个对程序来说不再有效的内存空间。

返回指针:const int *func3(); // 注意千万不要返回指向局部对象的指针,因为一旦函数结束,局部对象被释放,返回的指针变成了指向一个不再存在的对象的悬垂指针。

5. const 在类中的使用

class A

{

public:

void func();

void func() const;

const A operator+(const A &) const;

private:

int num1;

mutable int num2;

const size_t size;

};

(1) 修饰成员变量

const size_tsize; // 对于const的成员变量,[1]必须在构造函数里面进行初始化;[2]只能通过初始化成员列表来初始化;[3]试图在构造函数体内对const成员变量进行初始化会引起编译错误。

例如:

A::A(size_tsz):size(sz) // ok:使用初始化成员列表来初始化

{

}

A::A(size_tsz)

(2) 修饰类成员函数

void func()const; // const成员函数中不允许对数据成员进行修改,如果修改,编译器将报错。如果某成员函数不需要对数据成员进行修改,最好将其声明为const 成员函数,这将大大提高程序的健壮性。

const 为函数重载提供了一个参考

class A

{

public:

void func(); // [1]

void func() const; // [2]:上一个函数[1]的重载

……

};

A a(10);

a.func();// 调用函数[1]

const Ab(100);

b.func();// 调用函数[2]

如何在const成员函数中对成员变量进行修改???

mutable

class A

{

public:

A::A(int i):m_data(i){}

void SetValue(int i) const { m_data = i; }

private:

mutable int m_data; // 这里处理

};

(3)修饰类对象

const Aa; // 类对象a 只能调用const 成员函数,否则编译器报错。

(4)修饰类成员函数的返回值

const Aoperator+(const A &) const; // 前一个const 用来修饰重载函数operator+的返回值,可防止返回值作为左值进行赋值操作。

例如:

A a;

A b;

A c;

a + b =c; // 出错: 如果在没有const 修饰返回值的情况下,编译器不会报错。

C和C++中const区别

1.只读变量 &
常量

在C语言中,被const修饰的就是常量吗?真的能不动如山吗?编译如下代码,你觉得如何?

const int a = 10;

int *pa = &a;

*pa = 20;

printf("%d/n",*pa);

printf("%d/n",a);

编译器并不会像你想的那样会报错,只是给出警告(warning C4090: “初始化”: 不同的“const”限定符)你运行时才发现,a的值已经被改掉了。变成了 20

关键字const并不能把变量变成常量!在一个符号前面加上限定符const只是表示不能被赋值,换句话说,它的值对这个符号来说是只读的,但是并不能防止通过程序的内部(或者说外部)的方法来修改这个值。

所在C语言中被const修饰的变量只是一个只读的变量而已。如:

const intn = 100;

int a
;(C不提倡这样写,可以用宏代替)

但是在C++中不是这样的,在C++中被const的修饰毫无疑问是常量,它的值在编译时就被确定了。

const int a = 10;

int *pa = &a;

*pa = 20;

printf("%d/n",*pa);

上面代码在C++中是错误的,肯定会出现编译错误。( error C2440: “初始化”: 无法从“const int *”转换为“int *” )

而下面代码在C++中是很普遍的。

const intn = 100;

int a
;

而且这样的表达是很普遍的很值得提倡的表示法(C++中不提倡使用宏,宏可以被常量、内联函数替代)。

在C++中的const属性是可以被去掉的,通过const_cast就可以强转掉。你试过这样的代码吗?

#include<iostream>

using namespacestd;

int main()

{

const int a = 10;

const int *pa = &a;

int* pb = const_cast<int*>(pa);

*pb = 20;

cout << *pa << endl;

cout << *pb << endl;

cout << a << endl;

return 0;

}

输出结果为

20

20

10

2. 内连接和外连接的区别

const variable 在定义时必须初始化,是文件内部可见。这是因为c++中,const变量默认是内连接的(internal linkage)。(原因见后)

也就是说它只能在定义它的文件内部使用,连接时其它编译单元看不见它。例如:

const int i = 0 ; // 而且编译器一般不为const variable分配内存,而是将它放符号表(symbol table),以便编译时实现常量折叠(constant folding)。

但是,若是进行如下定义:extern const int i;

则将强制编译器为变量分配内存空间。因为,extern 意味着使用外部链接(external linkage)。

当你对一个const variable 取地址时,也会进行内存分配。例如:

const int i = 9;

long address = (long ) &i;

由上面我们可以看出,编译器并不总是能够成功的避免为常量分配内存,上述两种情况就必须分配内存。所以const variable如果默认是外连接,就有可能导致同一个常量在不同的cpp文件中都分配了内存(比如多个文件中都要求取得一个常量的地址)。这就会让编译器认为同一常量出现重复定义而报错。

而如果常量默认为内连接,这就意味着该常量只在当前定义它的文件内部有效,而连接器不会试图去连接其他编译单元里的常量。这样,即使多个cpp文件中有相同名字的一个常量也不会发生冲突。如此,编译器就可有效的实现常量折叠(constant folding)

另外,有上面我们知道,在C++中,const int i = 0; i的值是在符号表里,这就意味着i的值是编译期间可见的。所以,如下代码是可行的:

const int i = 0;

const int j = i + 1; // ok! 因为i的值在编译时知道,j也是const

这里和C中的const有所不同,C中的const默认为外连接,所以总是会为其分配内存空间。这就意味着,在C中

const int bufsize = 100;

在编译期间,编译器并不知道 bufsize的值。所以,下面的代码有误:

const int bufsize = 100;

char buf[bufsize]; // error

还有一点不同的是:

const int bufsize;

这句代码在C中是可以的,编译器认为这是一个声明,某处有为这个常量分 配内存,但是在C++中,这句代码是不可以的。

可以有两种方式修改:

(1) const int bufsize = 100; //定义时初始化

(2) extern const int; // 当然,这句在C中也是可以的

////////////////////////////////////////////////////////////////////////////////////

在C语言中:

const int size;

这个语句是正确的,因为它被C编译器看作一个声明,指明在别的地方分配存储空间.但在C++中这样写是不正确的.C++中const默认是内部连接,如果想在C++中达到以上的效果,必须要用extern关键字.

C++中,const默认使用内部连接.而C中使用外部连接.

内连接:编译器只对正被编译的文件创建存储空间,别的文件可以使用相同的表示符或全局变量.C/C++中内连接使用static关键字指定.

外连接:所有被编译过的文件创建一片单独存储空间.一旦空间被创建,连接器必须解决对这片存储空间的引用.全局变量和函数使用外部连接.通过extern关键

字声明,可以从其他文件访问相应的变量和函数.

************************C++代码******************************

header.h

const int test = 1;

test1.cpp

#include

#include "header.h"

using namespace std;

int main()

{

cout << "in test1 :" << test << endl;

}

test2.cpp

#include

#include "header.h"

using namespace std;

void print()

{

cout << "in test2:" << test << endl;

}

以上代码编译连接完全不会出问题,但如果把header.h改为:

extern const int test = 1;

在连接的时候,便会出现以下错误信息:

test2 error LNK2005: "int const test" (?test@@3HB) 已经在 test1.obj 中定义

因为extern关键字告诉C++编译器test会在其他地方引用,所以,C++编译器就会为test创建存储空间,不再是简单的存储在名字表里面.所以,当两个文件同时包含header.h的时候,会发生名字上的冲突.

此种情况和C中const含义相似:

header.h

const int test = 1;

test1.c

#include

#include "header.h"

int main()

{

printf("in test1:%d\n",test);

}

test2.c

#include

#include "header.h"

void print()

{

printf("in test2:%d\n",test);

}

错误消息:

test3 fatal error LNK1169: 找到一个或多个多重定义的符号

test3 error LNK2005: _test 已经在 test1.obj 中定义

C++中,是否为const分配空间要看具体情况.

如果加上关键字extern或者取const变量地址,则编译器就要为const分配存储空间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: