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()相比,这种初始化并不必付出更多的开销。
很多编译器可以很容易把它优化成一个很快的过程