第八章 常量

C ++中的const默认为内部链接。也就是说const尽在const被定义过的文件里才是可见的,而在连接时不能被其他编译单元看到。当定义一个const时,必须赋予一个值给它,除非用extern做出了清楚的说明:(测试了下载.h里定义的const  在cpp里可用???)

extern const int buffersize;

通常C++编译器并不为const创建存储空间,相反把它这个定义保存在它的符号表里。

const int ii = 1;
//float f[i[3]]; //illegal
float f[ii];
struct S
{
 int i;
 int j;
};

const S s1;
const S s[] = {{1,2},{3,4}};
//double d[s1.j];//illegal
//double d[s[1].j];//illegal
int main() {}///:~


8.1.4 与C语言的区别

const 在C中是默认外部连接,C++默认是内部链接

8.2 指针

当使用带有指针的const时,有两种选择:const修饰指针正向的对象,或者const修饰在指针里的存储地址。

8.2.1指向const的指针

正如任何复杂的定义一样,定义指针的技巧是在标识符的开始处读它并从里向外读。

const修饰“最靠近”它的那个。这样要使正指向的元素不发生改变,得写一个像这样的定义:

const int* u;

从标识符开始读:“u是一个指针,它指向一个const int类型”。这里不需要初始化,以为u可以指向任何标示符(也就是说他不是一个const),但它所指的值是不能被改变的。

这是一个容易混淆的部分。有人可能认为:要想指针本身不变,即包含在指针u里的地址不能被改变,可简单的像这样吧const 从int的一边移向另一边:

int const* v;

并非所有的人都肯定地认为:应该都城“v是一个指向int的const指针”。然而,实际上应读成“v是一个指向恰好是const int的普通指针”。即const又把自己与int结合在一起,效果与前面定义的一样。两个定义是一样的,这一点容易使人混淆。为使程序更具有可读性,应该坚持使用第一种形式

8.2.2 const指针

使指针本身成为一个const指针,必须把const

8.2.3 赋值和类型检查

可以把一个非const类型变量的地址赋值给一个const指针,因为有时候不想改变可以改变的值

不可以把一个const变量的地址赋值给一个非const的指针,因为这样做就有可能通过被赋值的指针改变这个对象的值

当然,总能用强制类型转换进行这样的操作,但是这是一个不好的程序设计习惯

8.3函数参数和返回值

8.3.2.1临时变量

有时候,在求表达式的期间,编译器必须创建临时变量。临时变量自动创建成const,以防止程序员修改。

8.3.3 传递和返回地址

无论什么时候传递一个地址给一个函数,都应该尽肯能用const修饰它。

//:C08:ConstPointer.cpp
//Constant pointer arg/return

void t(int*){}

void u(const int* cip)
{
	//!*cip =2;//illegal modifies value
	int i = *cip; //ok  copy value
	//int* ip2 = cip;//illegal: non-const 不能把const的地址赋值给非const的指针
}

const char* v()
{
	//return address of static character array:
	return "result of function v()";
}

const int* const w()
{
	static int i;
	return &i;
}

int main()
{
	int x =0;
	int* ip = &x;
	const int* cip = &x;
	t(ip);//ok
	//t(cip);//not ok
	u(ip);//ok
	u(cip);//ok
	//char* cp = v();//not ok
	const char* ccp = v(); //ok
	//int* ip2 = w();//not  ok
	const int* const ccip =  w();//ok
	const int* cip = w();//ok
	//int* const cip2 = w();//not ok
	//*w() = 1;// not ok
}


函数u()带一个const指针,所以它可以接受两种类型的参数。这样,带const指针参数的的函数比不带const指针参数的函数更具有一般性

8.3.3.1 标注参数传递

临时变量按引用传递给一个函数时,这个函数的参数必须是const引用

//:C08:ConstTemporary.cpp
//Temporaries are const
class X {};
X f() {return X();}//return by value

void g1(X &){}//pass by non-const reference
void g2(const X &){}//passed nu const reference

int main()
{
	//Error:const temporary created by f():奇怪g1(f())居然好使
	g1(f());
	g2(f());
}

 

8.4类

8.4.1类里的const

8.4.1.1 构造函数初始化列表
//:C08:ConstInitialization.cpp
//Initializing const in classes
#include <iostream>
using namespace std;
class Fired
{
	const int size;
public:
	Fired(int sz);
	void print();
};

//Fired::Fired(int sz)
//{
//	size = sz;
//}

Fired::Fired(int sz):size(sz){}
void Fired::print()
{
	cout << size << endl;
}

int main()
{
	Fired a(1),b(2),c(3);
	a.print();
	b.print();
	c.print();
}
 
//:C08:EncapsulatingTypes.cpp
#include <iostream>
using namespace std;
class Integer
{
	int i;
public:
	Integer(int ii = 0);
	void print();
};

Integer::Integer (int ii):i(ii){}
void Integer::print()
{
	cout << i << ' ';
}
int main()
{
	Integer i[100];
	for(int j =0; j < 100; j++)
	{
		i[j].print();
	}
	getchar();
}///:~


在main()中的Integer 数组元素都被自动的初始化为零。与for循环和memset()相比,这种初始化并不必付出更多的开销。

很多编译器可以很容易把它优化成一个很快的过程

8.4.2 编译器期间类的常量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值