const那些事
-
const作用
- 定义常量
- 类型检查
const
与#definde
宏定义的区别:const常量具有类型,编译器可以进行安全检查;#define宏定义没有数据类型,只是简单的字符串替换,不能进行安全检查。[issue]https://github.com/Light-City/CPlusPlusThings/issues/5- const只有在修饰枚举和整型变量时才能作为常量表达式
- 防止修改,起保护作用,增加程序健壮性
- 可以节省空间,避免不必要的内存分配
const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。
-
const对象默认为文件局部变量
注意:非const变量默认为extern。要使const变量能够在其他文件中访问,必须在文件中显式地指定它为extern。
小结:未被const修饰的变量不需要extern显式声明!而const常量需要显式声明extern,并且需要做初始化!因为常量在定义后就不能被修改,所以定义时必须初始化。//file1.cpp #include<iostream> using namespace std; extern const int a; extern int b; int main() { cout<<a<<b<<endl; return 0; } //file2.cpp extern const int a = 10;//需要显式声明并且初始化 int b;//不需要显式声明
-
指针与const
const char * a; //指向const对象的指针或者说指向常量的指针。 char const * a; //同上 char * const a; //指向类型对象的const指针。或者说常指针 const char * const a; //指向const对象的const指针。
小结:如果const位于的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于的右侧,const就是修饰指针本身,即指针本身是常量。
- 指向常量的指针
const int *ptr;//const定义int类型,所以ptr不用赋初值且ptr可 //改变指向的对象; *ptr = 10;//error
允许把非const对象的地址赋给指向const对象的指针:
const int *ptr; int a = 10; ptr = &a;//ok。但是不能通过ptr指针来修改a的值
不能使用指向const对象的指针修改基础对象,如果该指针指向了非const对象,可用其他方式修改其所指的对象:
const int *ptr; int a = 10; ptr = &a; int *p = &a; *p = 20;//用一个普通指针指向该基础对象,使用普通指针修改即可。
- 常指针
const指针必须进行初始化,且const指针的值不能修改
#include<iostream> using namespace std; int main() { int a=10,b = 11; int* const ptr = &a; *ptr = 20;//ok,可以改变基础变量的值 cout<<*ptr<<endl; ptr = &b;//error,不可以改变指向 return 0; }
不能让常指针指向const对象
-
函数中使用const
- const修饰函数返回值
const int func1();
const int* func1();//指针指向的内容不变。???什么情况下用??
int* const func1();//指针本身不变。???什么情况下用??
- const修饰函数参数
(1)传递过来的参数及指针本身在函数内不可变,无意义!
void func(const int var); // 传递过来的参数不可变 void func(int *const var); // 指针本身不可变
(2)参数指针所指内容为常量不可变
//src是输入参数,dst是输出参数 void StringCopy(char *dst, const char *src);
(3)参数为引用,为了增加效率同时防止修改。
void func(const A &a)//引用传递有可能改变参数a,这是我们不期望的。解决这个问题很容易,加const修饰即可
小结:对于非内部数据使用引用传递会提高效率,对内部数据“引用传递”和“值传递”效率差不多,因为内部数据不存在构造、析构的过程,且复制较快。对于内部数据类型的输入参数,不要将“值传递”的方式改为“const 引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性
-
类中使用const
在一个类中,任何不会修改数据成员的函数都应该声明为const类型。使用const关键字进行说明的成员函数,称为常成员函数。只有常成员函数才有资格操作常量或常对象,没有使用const关键字明的成员函数不能用来操作常对象- 类中的const成员变量必须通过初始化列表进行初始化
- const对象只能访问const成员函数,非const对象可以访问任意的成员函数,包括const成员函数。
- const对象默认调用const成员函数。
const成员变量:只读变量,只能通过初始化列表初始化
const成员函数:不能直接改变成员函数的值,智能调用const成员函数
const对象只能调用const成员函数- const成员变量可以用以下方式初始化(c++11)
#include<iostream> #include<string> using namespace std; class apple { public: apple(); static const int a = 10;//内部直接初始化 int b = 20; const int c = 30;//内部直接初始化 static const int d; static int num;//static静态成员变量不能在类的内部初始化。 //在类的内部只是声明,定义在类定义体的外部 }; apple::apple(){} const int apple::d = 40;//外部初始化 int main() { apple a1; cout<<a1.a<<endl; cout<<a1.b<<endl; cout<<a1.c<<endl; cout<<a1.d<<endl; return 0; }