我在C++:18篇里说过const的用法,这里我有必要再提升进阶下const的理解。

因为你可能只知道他是怎么用的,但是他为什么这样用,其他用法呢?


首先回顾下const有什么主要的作用?

(1)可以定义const常量,具有不可变性。

(2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。

(3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。同宏定义一样,可以做到不变则已,一变都变

(4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。

(5) 为函数重载提供了一个参考。

(6) 可以节省空间,避免不必要的内存分配。例如:

#define PI 3.14159 //常量宏

const doulbe Pi=3.14159; //此时并未将Pi放入ROM中 ......

double i=Pi; //此时为Pi分配内存,以后不再分配!

double I=PI; //编译期间进行宏替换,分配内存

double j=Pi; //没有内存分配

double J=PI; //再进行宏替换,又一次分配内存!

const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。

(7) 提高了效率。编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。 



常量与数组的组合有什么特殊吗? 我们给出下面的代码:


有什么问题吗?对了,编译通不过!为什么呢?

const可以用于集合,但编译器不能把一个集合存放在它的符号表里,所以必须分配内存。在这种情况下,const意味着“不能改变的一块存储”。然而,其值在编译时不能被使用,因为编译器在编译时不需要知道存储的内容。自然,作为数组的大小就不行了。


在函数中声明的形参,在函数被调用时会得到实参的值。但是如果在类中呢?


class Demo{
const int ci;
public:
void get_ci()
{
return ci;
}
};


当直接用这个类定义一个对象时,会出错,提示没有初始化const成员变量值 且提示ci是一个只读的变量,const用于类中成员变量时,将类成员变为只读属性(只读:不能出现在“=”的左边,但在类中仍可以用一个指针来修改其值。) 所以不可以直接在类的构造函数中初始化const 的成员。

 const成员变量只可以初始化列表中初始化


你再看看下面的例子:

 

class Demo { 
public:
A(int i=0):test[2]({1,2}) {}//你认为行吗?
private:
const int test[2];
};


vc6下编译通不过,为什么呢


this指针是不是const类型的?

this指针是一个很重要的概念,那该如何理解她呢?也许这个话题太大了,那我们缩小一些:this指针是个什么类型的?这要看具体情况:如果在非const成员函数中,this指针只是一个类类型的;如果在const成员函数中,this指针是一个const类类型的;如果在volatile成员函数中,this指针就是一个volatile类类型的。怎么理解,卖个关子,我将在下一篇文章解释。


const到底是不是一个重载的参考对象?

先看一下下面的例子:

class A {


......


void f(int i) {......}//一个函数


void f(int i) const {......}//上一个函数的重载


......


};


上面是函数重载是没有问题的了,那么下面的呢?

class A {


......


void f(int i) {......}//一个函数


void f(const int i) {......}//?????


......


};

这个是错误的,编译通不过。那么是不是说明内部参数的const不予重载呢?再看下面的例子:

class A {


......


void f(int& ) {......}//一个函数


void f(const int& ) {......}//?????


......


};

这个程序是正确的,看来上面的结论是错误的。

为什么会这样呢?这要涉及到接口的透明度问题。按值传递时,对用户而言,这是透明的,用户不知道函数对形参做了什么手脚,在这种情况下进行重载是没有意义的,所以规定不能重载!当指针或引用被引入时,用户就会对函数的操作有了一定的了解,不再是透明的了,这时重载是有意义的,所以规定可以重载。 


什么情况下为const分配内存?

以下是我想到的可能情况,当然,有的编译器进行了优化,可能不分配内存。

A、作为非静态的类成员时;

B、用于集合时;

C、被取地址时;

D、在main函数体内部通过函数来获得值时;

E、const的 class或struct有用户定义的构造函数、析构函数或基类时;。

F、当const的长度比计算机字长还长时;

G、参数中的const;

H、使用了extern时。


与static搭配会不会有问题?假设有一个类:

class A {


public:


......


static void f() const { ......}


......


};


 我们发现编译器会报错,因为在这种情况下static不能够与const共存!为什么呢?因为static没有this指针,但是const修饰this指针,所以...


class A {
public:
A(int i=0):test(i),c('a') { }
private:
char c;
const int test;
};
int main()
{
A a(3);
A* pa=&a;
char* p=(char*)pa;
int* pi=(int*)(p+4);//利用边缘调整
*pi=5;//此处改变了test的值!
return 0;
}



要点: 对于优化做的比较好的编译器,代码const int i = 1;

当后面用到变量i 的时候,编译器会优化掉对i 的存取,而直接使用立即数1



读到这里的粉丝可能觉得我这个人比较变态,总喜欢写一些奇奇怪怪的代码来折腾人,没错,真正的游戏线上环境是复杂而且残酷的,必须得这么折腾才能长记性,最后我再折腾下各位,请看如下代码:

void main() 
{
const int i = 1;
*(const_cast<int*>(&i)) = 2;
cout << *(int*)&i << endl;
cout << i << endl;
}


为什么i和*(int*)&i的结果不一样,二者有什么区别?欢迎留言哈,我将统一解答