const
1、修饰变量(局部变量或全局变量)
const int temp1 = 1; //temp1为常量,不可变,必须设置初值
int const temp2 = 2; //temp2为常量,不可变
2、修饰指针
主要看const在*的前后,在前则指针指向的内容为常量,在后则指针本身为常量;
const int *ptr; //*ptr为常量(ptr 为指向常量的指针)
int const *ptr; //*ptr为常量(ptr 为指向常量的指针)
int* const ptr; //ptr为常量 (ptr 为指针常量,地址不可修改,必须设置初值)
const int * const ptr; //*ptr、ptr均为常量(ptr 为指向常量的指针,也是指针常量,必须设置初值)
3、修饰函数
在函数声明中,const可以修饰函数的返回值,也可以修饰具体某一个形参;
(1)修饰形参时,在函数体内,按照const所修饰的部分进行常量化,避免了拷贝和避免了函数对值的修改;
void func1(const int Var); // 传递过来的参数在函数内不可变
void func2(const char* Var); // 参数指针所指内容为常量
void func3(char* const Var); // 参数指针为常指针
void func4(const int& Var); // 引用参数在函数内为常量
(2)修饰函数返回值时,该返回值只能被赋给加const 修饰的同类型指针。一般情况下,const修饰返回值多用于操作符的重载。通常不建议用const修饰函数的返回值类型为某个对象或某个对象引用的情况;
const int add(int a, int b);//返回一个常量,需要定义一个对应类型的常量去接收
4. const修饰类的成员
(1)const成员函数表示该成员函数不能修改类对象中的任何数据成员变量的值。一般const写在函数的后面,形如:
class CExample{
void func() const;//常成员函数,不能修改对象中的成员变量,也不能调用类中任何非const成员函数;
}
(2)修饰成员变量,需要在申明时进行初始化。(不建议使用)
如果某个成员函数不会修改成员变量,那么最好将其声明为const,因为const成员函数不会对数据进行修改,如果修改,编译器将会报错;
(3)const修饰类对象,其对象中的任何成员都不能被修改,且该对象的任何非const成员函数都不能调用,因为任何非const成员函数都会有修改成员变量的可能。
class A {
public:
const int a = 1; //修饰成员变量,需要在申明时进行初始化
int b = 0;
void print(int i) const // 常成员函数,不得修改类中的任何数据成员的值
{
printf("hello %d\n", i);
}
void change(int i) // 普通成员函数
{
b = i;
}
};
int main()
{
const A obj;
obj.print(2);
//obj.change(2); // 错误,不能调用非const修饰的成员函数
//obj.b = 2; // 错误,可以访问变量,但是不能修改任何成员的值
printf("%d\n", obj.a);
printf("%d\n", obj.b);
return 0;
}
5.const常量与define宏定义的区别
(1)处理阶段不同:
define是在预处理阶段,define常量从未被编译器看见,因为在预处理截断就已经替换了;
const常量在编译阶段使用。
(2)类型和安全检查不同
define没有类型,不做任何检查,仅仅是字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误
const常量有明确的类型,在编译阶段会进行类型检查;
(3)存储方式不同
define是字符替换,有多少地方使用,就会替换多少次,不会分配内存;
编译器通常不会为const常量分配空间,只是将它们保存在符号表内,使他们成为一个编译期间的一个常量,没有读取内存的操作,效率也很高;
6.mutable关键字
在C++中,mutable是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中,甚至结构体变量或者类对象为const,其mutable成员也可以被修改:
class A {
public:
const int a = 1;
mutable int b = 0;
void print(int i) const {
printf("hello %d\n", i);
}
void change(int i) {
b = i;
}
};
int main()
{
A obj1;
obj1.print(2);
obj1.change(2);
obj1.b = 2;
const A obj2;
obj2.print(2);
//obj2.change(2); // 错误,const类对象不能访问非const修饰成员函数
obj2.b = 2;
return 0;
}
注意:mutable只能修饰非静态数据成员;
7、const_cast 强制转换,用于修改类型的const或volatile属性
用法:const_cast<type_id> (expression)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
(1)常量指针被转化成非常量的指针,并且仍然指向原来的对象;
(2)常量引用被转换成非常量的引用,并且仍然指向原来的对象;
(3)const_cast一般用于修改底指针。如const char *p形式。
int a = 1;
int* const ptr = &a;
int *p = const_cast<int*>(ptr);
static
1. 修饰普通变量,修改变量的存储区域和生命周期,使变量存储在静态区,在 main 函数运前就分配了空间,如果有初始值就初始值初始化它,如果没有初始值系统默认值初始化它。
2. 修饰普通函数,表明函数的作用范围,仅在定义该函数的文件内才能使用。在多人开发项目时,为了防止与他人命令函数重名,可以将函数定位为 static。
3. 修饰成员变量,修饰成员变量使所有的对象只保存一个该变量,是类实例之间共享的。且不需要生成对象就可以访问该成员。
4. 修饰成员函数,修饰成员函数使得不需要生成对象就可以访问该函数,但是在 static 函数内不能访问静态成员。
修饰类成员的优点:
(1)不同的类有自己的静态资源,这可以实现静态资源分类。
(2)避免不同的类之间有重名的静态变量名、静态方法名。
(3)避免静态资源类无限膨胀。
(4)不需要生成对象就可被调用
(5)静态变量是全局变量
(6)任何一个对象修改静态变量的值,那么所有的该类的对象的静态成员变量的值都改变
注意:
(1)静态资源是类初始化的时候加载的,而非静态资源是类new的时候加载的
(2)静态成员函数只能引用静态成员变量,不能引用非静态成员变量。而非静态成员可以访问静态成员变量。
(3)不能使用this引用