最近买了本C++之父的《C++程序设计语言》打算重学C++。废话不多说,上正题。
C++中的const
(1)简单的定义一个常量
const int number1=1; int const number2=1;
这两句是等同的,都是声明了一个值为1的整型常量。需要注意的是,定义一个常量要同时给之赋值。
const int number3; //error, uninitialized const number3
像上述这条语句,是编译不过的。
(2)定义常量指针和指针常量
const int* ptr1; const* int ptr2; int const *ptr3;
int * const ptr4; //error, uninitialized const ptr4
一共4条语句,包含两个不同的意思,因为const可以修饰指针,也可以修饰指针指向的内容。前三句声明指向常量的指针,简称常量指针。也就是说,ptr1,ptr2,ptr3三个指针都指向常量。最后一句表示ptr4是指针常量,即ptr4不可以修改以指向别的对象。这通常比较不容易分辨,我的方法是看const 和*相对位置,比如const *就是声明指向常量的指针,*const就是声明指针常量。
int * const *ptr5; //error,uninutialized const ptr5
毫无疑问,上面这条语句的意思是“指向常量指针的指针常量”。即ptr5不能指向其他内容,且ptr5指向的对象不能被修改。
(3)C++不愧是宇宙最难的语言。看看下面两条语句。
const int number=0; int* ptr=&number; //error
普通指针不能被赋值为指向常量。这是因为一旦这样赋值,就意味着下面这条语句可以修改常量。
*ptr=1;
再看看下面这两条语句。
int number; const int* ptr=&number; //ok
这是合法的,换句话说,常量指针可以指向非‘常量。
(4)上面这些内容和C一样。下面来谈谈和C不一样的,引用。
定义一个引用。
type& object2=object1;
type可以是任何类型,这样相当于给object1起了一个别名object2,对object2所施加的操作会作用到object1上。这里object1也必须是type类型,并且必须是一个左值。
但是定义一个常量的引用就不同了。
const type& object2=object1;
object1仍然可以是一个左值,但还可以是一个常量,甚至还可以不是type类型。上面这条语句类似于下面这两条语句。
type temp=type(object1); const type& object2=temp;
需要注意的是,类似并不表示全等。举个例子:
int number=0; /*1*/const int& refer=number; //refer=0 /*2*/int temp=int(number); const int& _refer=temp; number=1000; //refer=1000, _refer=0
以此推测,当object1与object2类型相同时,此类赋值与普通引用赋值一样(小小的不同是不能改变直接显式改变object2),当两者类型不同时,此类赋值与中间变量赋值一样(通过temp)。
(5)const在函数中的应用
char* strcpy(char* ,const char* );
当函数参数用const修饰时,表示在这个函数中,此参数不改变,如上。
需要注意的是,因为普通引用没有类型转换机制,所以函数参数最好别为普通引用,避免如下尴尬情况的出现。
void function(int& refer);
void _function(const int& refer);
function(3.14159); //error
function(3.14159); //better
这也正是C++之父的建议。
Be suspicious of non-const reference arguments; if you want the function to modify its arguments, use pointers and value return instead.
------Bjarne Stroustrup《the C++ programming language》
(6)再来看个奇怪的函数。
class a_class{ int data1; int data2; public:
void _function(){
//change data1 //normal
} void function()const{
//change data1 //illegal
} };
const 在函数参数之后,这是啥意思?
众所周知,成员函数有一个隐藏参数, this,代表调用此函数的对象。上面的函数_function相当于:
void _function(a_class *this);
那么问题来了,this这个参数是隐藏的,如何才能做到让编译器识别并禁止改变此对象呢?即如何做到如下效果:
void _function(const a_class *this);
直接这样写肯定不行,那能不能如下所示呢?
void _function(const );
编译器会认为这是另外一个参数的修饰(并且会报错因为没有类型!) ,而不是this。
于是解决方法就是:
void _function()const;
总结一下,上面函数声明的意思就是,禁止在此函数中修改调用此函数的对象的内容。
(7)最后说说'类型转换
要了解const,当然不能不了解C++的类型转换const_cast<datatype>(data)
此类型转换专门用来将const类型的指针或引用转换为非const类型,如下:
int number=1; const int& refer=number; int& _refer=const_cast<int&>(refer); refer=12; //error _refer=12; //ok, now refer==12, _refer==12, number==12
当原本数据类型不是常量时,const_cast可以正常工作。那么,如果原本类型就是常量,那会发生什么,如下:
const int number=1; const int& refer=number; int& _refer=const_cast<int&>(refer); //undefined behavior refer=12; //error _refer=12; //ok, now refer==12, _refer==12, number==1 in g++
当声明一个常量时,编译器可能会采取某些形式的内存保护措施以确保其内容不被改变。所以这种情况是未定义的,最好不要这样做。