关于const的相关知识,在苏宁面试中被问过,当时只回答了常量的含义,其他含义也清楚,但是由于没有准备,所以回答的不是很好,现记录一下关于const的相关知识,如果错误,欢迎指导。
一、常量:
在c++中,const把一个对象转换成常量,定义后就不能修改了,因此,定义时,必须初始化。
需要注意的是,在全局作用域声明的const变量是定义该对象文件的局部变量,在存在那个文件中,不能被其他文件访问。
二、const在c与c++中的区别
在C中,常量占用存储,但是c编译器不能把const看做编译期间的常量,比如下面就是错误的
const bSize = 100;
int b[bSize];//报错
c把他看做声明,指明在别的地方申请内存,c默认const是外部链接的,而c++默认是内部链接的,如果c++想改成和c一样需要extern把链接改成外部链接
extern const bSize;
所以呢,在c语言中const不是很有用,一般还是用#define
//在c语言中,值替换的典型用法
#define bSize 100
//在c++中,可以写成这样
const bSize = 100;
//或者
const int bSize = 100;
三、使用const比#define有更多优点
1)const常量有数据类型,宏常量没有数据类型,前者会进行类型安全检查,后者只是单纯的字符替换,可能会有想不到的错误
const int a=100;有int 型安全检查
2)const常量会导致产生更小的目标代码,如预处理器可能会盲目将宏名称bSize替换成值100,可能会导致出现多个100的备份,但是常量不会出现这种情况
3)const还可以执行常量折叠,比如编译时,将常量表达式计算求值,并且用求得的替换表达式,放入常量表
所以呢,c++中,应该用const替代#define
四、指针和const修饰符
这边有两种情况,
一种是指针指向const的对象,则不允许用指针改变所指的const的值,如
const double *ptr;
double const *ptr;//这两个效果是一样的
另外一种是指针本身成为一个const指针,这时候指针本身是一个const指针,编译器要求给它一个初始化值,初一,指针不可以变,但是指针指向的值是可以改变的
*ptr = 2.0
具体我来举个小例子
int main()
{
double value = 1.0;
double *ptr = &value;//ptr值可以改变,value的值也可以改变
const double *ptr1 = &value;//ptr可以改变,但是ptr指向的value的值不可以变
double *const ptr2 = &value;//ptr值不可以变,但是可以通过ptr改变value的值
const double * const ptr3=&value;//这种情况,两个都不能变
return 0;
}
五、修饰函数参数与返回值
在函数声明式中,const可以和函数返回值、参数、函数自身(成员函数可以)关联
当修饰返回值是值类型时,对内部数据来说,返回是否是常量关系不大(我认为这是给用户自己看的吧,有时候处理用户自定义的类型时,返回值不为常量有时会对客户造成困扰)。
当返回值是指针时,要注意,函数不能返回局部变量栈对应的指针,函数返回后,栈就被清理了,返回的指针可以指向堆中分配的存储空间的指针或指向静态存储区的指针
如下面是有效的
char *getM(void)
{
char *p = "hello";
return p;
}
而这个则是可能会乱码的
char *getM(void)
{
char p[]="hello";
return p;
}
因为p是一个数组,分配在栈上,可以通过添加static或者手动在堆中开地址实现。
const用来修饰函数的参数
如果函数的参数是值传递的,可以用const限定参数,告诉编译器,参数在函数体内不会改变,如:
int fun(const int i);
注意,这样会报错的
int f(int *a);
const int a = 1;
f(&a)报错
因为,fun只能接受非const的形参,但是换成const 形参,则const 和非const的实参都能被接受
六、const在类中的使用
const成员函数,
确保该成员函数可以作用于const对象身上,const成员函数不能修改调用该函数的对象(mutable成员除外,跟类状态无关的可变的),const只能调用const,非const可以调用他非const和const,如果不存在const成员函数,const对象操作比较困难,使用const成员函数,可以对const对象产生操作
struct base
{
void f1();
void f2() const;
};
const数据成员
常量数据成员(常量成员变量),必须要再构造函数的初始化列表中进行初始化,不同对象的const成员是可以不同的。如例子
struct test
{
public:
test(int _a) : a(_a) {};//构造函数初始化
public:
const int a;//只能在够着函数初始化表中初始化
static int b;//在类中实现文件定义,在类外初始化
const static int c;//c为整型时可以在此处初始化,但仍然要在类体外定义,注意,c非整型时,不能再这边初始化
};
int test::b = 1;//static成员变量不能再构造函数初始化列表中初始化,因为不属于任何一个对象
const int test::c = 2;//给const static成员变量赋值时,不需要加static修饰,但是需要加const修饰
int main()
{
test t1(10);
cout << t1.a << endl;
system("pause");
return 0;
}